服务端只调用GenericMediaServer::ClientConnection类构造函数一次,在RTSPServer的基类GenericMediaServer的构造函数中,调用了turnOnBackgroundReadHandling并将其静态函数incomingConnectionHandler关联到fServerSocket。这样当有VLC客户端通过rtsp播放的时候,由于BasicTaskScheduler0::doEventLoop循环调用BasicTaskScheduler::SingleStep函数,执行刚刚关联的静态函数并继而调用同名函数进而调用GenericMediaServer::incomingConnectionHandlerOnSocket函数,在该函数中会调用createNewClientConnection函数。由于createNewClientConnection函数是GenericMediaServer类的虚函数,所以最终调用RTSPServerSupportingHTTPStreaming::createNewClientConnection函数创建RTSPServerSupportingHTTPStreaming::RTSPClientConnectionSupportingHTTPStreaming类对象,这个类继承自RTSPServer::RTSPClientConnection,而这个类又继承自GenericMediaServer::ClientConnection类。所以执行该构造函数一次。
在GenericMediaServer::ClientConnection类的构造函数中,和GenericMediaServer构造函数中一样,将ClientConnection类的静态函数incomingRequestHandler关联给这个客户连接socket。这样当客户端发送rtsp消息后,服务端就可以通过该静态函数作为响应入口来响应。该静态函数会调用同名函数即GenericMediaServer::ClientConnection::incomingRequestHandler,在该函数中先读取客户端发来的rtsp消息,然后调用handleRequestBytes函数响应,该函数为虚函数,实际调用的是RTSPServer::RTSPClientConnection::handleRequestBytes。当用vlc来请求一个Live555的264文件时,如果能正常播放则流程如下。其中在Live555服务端共调用RTSPServer::RTSPClientSession类构造函数一次,是在RTSPServer::RTSPClientConnection::handleRequestBytes函数中处理客户端发来的"Setup"消息的过程中,然后调用RTSPServer::RTSPClientSession::handleCmd_SETUP函数。在响应"Setup"消息过程中创建RTSPServer::RTSPClientSession对象,调用GenericMediaServer::createNewClientSessionWithId函数,在该 函数中首先生成一个随机值,然后以该随机值作为参数调用虚函数createNewClientSession,即执行RTSPServer::createNewClientSession来创建RTSPServer::RTSPClientSession对象。
其中在Live555服务端共调用ServerMediaSession类构造函数两次,第一次是在响应"Describe"消息的过程中,RTSPServer::RTSPClientConnection::handleCmd_DESCRIBE函数中首先调用GenericMediaServer::lookupServerMediaSession,该函数为虚函数所以会调用DynamicRTSPServer::lookupServerMediaSession函数,在该函数中首先用streamName作为参数调用基类的函数,如果没有找到就构造ServerMediaSession类对象并以streamName保存到基类的hash表fServerMediaSessions中,这样下次调用lookupServerMediaSession即可以查到。
在DynamicRTSPServer::lookupServerMediaSession函数中调用同文件中的静态函数createNewSMS,该函数调用ServerMediaSession类的构造函数,然后调用H264VideoFileServerMediaSubsession::createNew创建对象并作为参数调用ServerMediaSession::addSubsession函数。
第二次调用ServerMediaSession类构造函数是在响应"Setup"消息的过程中,在创建了RTSPServer::RTSPClientSession对象后,调用该对象的handleCmd_SETUP函数,即RTSPServer::RTSPClientSession::handleCmd_SETUP函数中,同样首先调用GenericMediaServer::lookupServerMediaSession,由于在响应"Describe"消息已经创建了ServerMediaSession类对象,所以DynamicRTSPServer::lookupServerMediaSession函数中是可以获取到这个对象的,但是在该函数中首先将之前的这个ServerMediaSession类对象移除,然后再调用静态函数createNewSMS,同在处理"Describe"消息中的流程一样,最终会调用ServerMediaSession类构造函数并保存到基类GenericMediaServer的hash表fServerMediaSessions中。之所以要先删除再添加的注释为"Remove the existing "ServerMediaSession" and create a new one, in case the underlying file has changed in some way"。这第二次调用ServerMediaSession类构造函数产生的对象在RTSPServer::RTSPClientSession::handleCmd_SETUP函数中赋值给RTSPServer::RTSPClientSession的基类GenericMediaServer::ClientSession中的成员ServerMediaSession* fOurServerMediaSession;而且注释为"We're accessing the "ServerMediaSession" for the first time."。然后根据ServerMediaSession对象包含的ServerMediaSubsession对象个数fSubsessionCounter来初始化RTSPServer::RTSPClientSession类的成员变量fStreamStates。这是一个指针对象,指向一个结构体数组,其中数组的每个元素代表一个子会话即ServerMediaSubsession对象。然后又会调用getStreamParameters,又因为该函数为虚函数,所以执行OnDemandServerMediaSubsession::getStreamParameters,该函数中首先创建继承自FramedSource类的H264VideoStreamFramer对象,然后又创建继承自RTPSink类的H264VideoRTPSink对象,然后以这两个对象创建StreamState对象来作为RTSPServer::RTSPClientSession类的成员fStreamStates所指的数组中子session的关联的void* streamToken;。然后将目的地址保存在子session的成员变量中,即OnDemandServerMediaSubsession类中的保护成员HashTable* fDestinationsHashTable;中。
下图所示为一次正常的客户端申请播放264视频所交互的rtsp消息及部分类的继承关系: