精通
英语
和
开源
,
擅长
开发
与
培训
,
胸怀四海
第一信赖
void RTSPServer::RTSPClientSession::handleCmd_SETUP(
char const* cseq,
char const* urlPreSuffix,
char const* urlSuffix,
char const* fullRequestStr)
{
for (unsigned i = 0; i < fNumStreamStates; ++i) {-----此处遍历ServerMediaSubsession,创立fStreamStates。每一个tracknum对应一个ServerMediaSubsession
subsession = iter.next();
fStreamStates[i].subsession = subsession;
fStreamStates[i].tcpSocketNum = -1; // for now; may get set for RTP-over-TCP streaming
fStreamStates[i].streamToken = NULL; // for now; it may be changed by the "getStreamParameters()" call that comes later
}
}
ive555 中有两个 streamstate,一个是类 StreamState ,一个是此处的结构 struct streamState 。 类 SteamState 就 是 streamToken , 而 struct streamState 中 保 存 了MediaSubsession (即 track) 和类 StreamState 的对应。类 StreamState 代表一个真正流动起来的数据流。这个数据流是从源流到 Sink 。客户端与服务端的一个 rtp 会话中,有两个数据流,服务端是从 XXXFileSouce 流到 RTPSink,而客户端则是从 RTPSource 流到 XXXFileSink 。建立数据流的过程就是把 Source 与 Sink 连接起来。为何不把 StreamToken 保存在 MediaSubsession 中呢?看起来在 struct streamState中是一个 MediaSubsession 对应一个 streamToken 呀? 因为 MediaSubsession 代表一个 track 的静态数据,它是可以被其它 rtp 会话重用的。比如不同的用户可能会连接到
同一个媒体的同一个 track 。所以 streamToken 与 MediaSubsession 独立存在,只是被 RTSPClientSession
streamToken 的建立过程存在于函数 subsession->getStreamParameters()中,让我们看
getStreamParameters是定义在ServerMediaSubsession类中的纯虚函数,其实现在子类OnDemandServerMediaSubsession中。这个函数中将完成source,RTPSink的创建工作,并将其与客户端的映射关系保存下来。
void OnDemandServerMediaSubsession
::getStreamParameters(unsigned clientSessionId, .......)
{
/------------------------------------------------------------------------------------------------/创建一对groupsocks实例,分别用于传输RTP、RTCP 类 Groupsock:这个是放在单独的库 Groupsock 中。它封装了 socket 操作,增加了多
------------------------------------------------------------------------------------------------播放支持和一对多单播的功能.
------------------------------------------------------------------------------------------------//RTP、RTCP的端口号是相邻的,并且RTP端口号为偶数。初始端口fInitialPortNum = 6970,
------------------------------------------------------------------------------------------------//这是OnDemandServerMediaSubsession构造函数的缺省参数
// Normal case: We're streaming RTP (over UDP or TCP). Create a pair of
// groupsocks (RTP and RTCP), with adjacent port numbers (RTP port number even):
NoReuse dummy; // ensures that we skip over ports that are already in use
for (portNumBits serverPortNum = fInitialPortNum; ; serverPortNum += 2) {
struct in_addr dummyAddr; dummyAddr.s_addr = 0;
RTPSink* rtpSink = NULL;
serverRTPPort = serverPortNum;
rtpGroupsock = new Groupsock(envir(), dummyAddr, serverRTPPort, 255);
serverRTCPPort = serverPortNum+1;
rtcpGroupsock = new Groupsock(envir(), dummyAddr, serverRTCPPort, 255);
------------------------------------------------------------------------------------------------//创建RTPSink,与source类似,在处理DESCRIBE命令进行过,RTPsink到底起什么作用??继续往下看
unsigned char rtpPayloadType = 96 + trackNumber()-1; // if dynamic
rtpSink = createNewRTPSink(rtpGroupsock, rtpPayloadType, mediaSource);
udpSink = NULL;
}
// Turn off the destinations for each groupsock. They'll get set later
// (unless TCP is used instead):
if (rtpGroupsock != NULL) rtpGroupsock->removeAllDestinations();
if (rtcpGroupsock != NULL) rtcpGroupsock->removeAllDestinations();
------------------------------------------------------------------------------------------------//重新配置发送RTP 的socket缓冲区大小
if (rtpGroupsock != NULL) {
// Try to use a big send buffer for RTP - at least 0.1 second of
// specified bandwidth and at least 50 KB
unsigned rtpBufSize = streamBitrate * 25 / 2; // 1 kbps * 0.1 s = 12.5 bytes
if (rtpBufSize < 50 * 1024) rtpBufSize = 50 * 1024;
increaseSendBufferTo(envir(), rtpGroupsock->socketNum(), rtpBufSize); //这个函数在groupsock中定义
}
---------------------------------------------------------------------------------//建立流的状态对像(stream token),其它包括sink、source、groupsock等的对应关系
------------------------------------------------------------------------------ //注意,live555中定义了两个StreamState结构,这里的StreamState定义为一个类。在RTSPServer中,
//定义了一个内部结构体StreamState,其streamToken成员指向此处的StreamState实例
// Set up the state of the stream. The stream will get started later:
streamToken = fLastStreamToken ------------------------------------------------------------------//streamToken 里面包含了rtpsink ,serverRTCPPort,serverRTPPort,rtpGroupsock
= new StreamState(*this, serverRTPPort, serverRTCPPort, rtpSink, udpSink,
streamBitrate, mediaSource,
rtpGroupsock, rtcpGroupsock);
}
------------------------------------------------------------//这里定义了类Destinations来保存目的地址、RTP端口、RTCP端口,并将其与对应的clientSessionId保存到哈希表
-----------------------------------------------------------------------------//fDestinationsHashTable中,这个哈希表是定义在OnDemandServerMediaSubsession类中
------------------------------------------------------------------------------------------------// Record these destinations as being for this client session id:
Destinations* destinations;
if (tcpSocketNum < 0) { // UDP
destinations = new Destinations(destinationAddr, clientRTPPort, clientRTCPPort);
} else { // TCP
destinations = new Destinations(tcpSocketNum, rtpChannelId, rtcpChannelId);
}
fDestinationsHashTable->Add((char const*)clientSessionId, destinations); //---------------------------------------clientSessionId
}
RTPSink作用
class RTPSink: public MediaSink {
unsigned char rtpPayloadType() const { return fRTPPayloadType; }----------------------------------------------------------熟悉rtp协议的多知道这个和rtp协议参数紧密结合
unsigned rtpTimestampFrequency() const { return fTimestampFrequency; }
void setRTPTimestampFrequency(unsigned freq) {