live555 源码分析:RTSPServer 组件结构
前面幾篇文章分析了 live555 中 RTSP 的處理邏輯,RTSP 處理有關組件的處理邏輯有點復雜,本文就再來梳理一下它們之間的關系。
live555 中 RTSP 處理有關組件關系如下圖:
事件和執行流程的源頭在 TaskScheduler。GenericMediaServer 對象在創建的時候,會向 TaskScheduler 注冊一個 server socket 及處理該 socket 上的事件的處理程序 GenericMediaServer::incomingConnectionHandler(void* instance, int /*mask*/)。
當有客戶端連接服務器時,觸發 server socket 上的事件處理器執行。此時會基于客戶端 socket 創建 ClientConnection 對象,及 RTSPClientConnection。 RTSPClientConnection 對象在創建過程中,會將該客戶端 socket 及
ClientConnection 中處理該 socket 上的事件的處理程序 GenericMediaServer::ClientConnection::incomingRequestHandler(void* instance, int /*mask*/) 注冊給 TaskScheduler。
在客戶端發送的 RTSP 請求數據到達之后,GenericMediaServer::ClientConnection 會讀取這些數據,并交給 RTSPServer::RTSPClientConnection::handleRequestBytes(int newBytesRead) 處理。
RTSPServer::RTSPClientConnection 解析 RTSP 請求,并處理 OPTIONS、DESCRIBE 和 “SETUP 等無需流媒體會話建立即可處理的請求。
RTSPServer::RTSPClientConnection 在處理 SETUP 請求時,會創建流媒體會話的 RTSPServer::RTSPClientSession,具體的會話建立過程都會被委托給后者處理。
需要會話建立之后才能處理的請求,也會被交給 RTSPServer::RTSPClientSession 處理。
這里來看一下 RTSPServer::RTSPClientConnection 的完整定義:
class RTSPServer: public GenericMediaServer { . . . . . . public: // should be protected, but some old compilers complain otherwise// The state of a TCP connection used by a RTSP client:class RTSPClientSession; // forwardclass RTSPClientConnection: public GenericMediaServer::ClientConnection {public:// A data structure that's used to implement the "REGISTER" command:class ParamsForREGISTER {public:ParamsForREGISTER(char const* cmd/*"REGISTER" or "DEREGISTER"*/,RTSPClientConnection* ourConnection, char const* url, char const* urlSuffix,Boolean reuseConnection, Boolean deliverViaTCP, char const* proxyURLSuffix);virtual ~ParamsForREGISTER();private:friend class RTSPClientConnection;char const* fCmd;RTSPClientConnection* fOurConnection;char* fURL;char* fURLSuffix;Boolean fReuseConnection, fDeliverViaTCP;char* fProxyURLSuffix;};protected: // redefined virtual functions:virtual void handleRequestBytes(int newBytesRead);protected:RTSPClientConnection(RTSPServer& ourServer, int clientSocket, struct sockaddr_in clientAddr);virtual ~RTSPClientConnection();friend class RTSPServer;friend class RTSPClientSession;// Make the handler functions for each command virtual, to allow subclasses to reimplement them, if necessary:virtual void handleCmd_OPTIONS();// You probably won't need to subclass/reimplement this function; reimplement "RTSPServer::allowedCommandNames()" instead.virtual void handleCmd_GET_PARAMETER(char const* fullRequestStr); // when operating on the entire servervirtual void handleCmd_SET_PARAMETER(char const* fullRequestStr); // when operating on the entire servervirtual void handleCmd_DESCRIBE(char const* urlPreSuffix, char const* urlSuffix, char const* fullRequestStr);virtual void handleCmd_REGISTER(char const* cmd/*"REGISTER" or "DEREGISTER"*/,char const* url, char const* urlSuffix, char const* fullRequestStr,Boolean reuseConnection, Boolean deliverViaTCP, char const* proxyURLSuffix);// You probably won't need to subclass/reimplement this function;// reimplement "RTSPServer::weImplementREGISTER()" and "RTSPServer::implementCmd_REGISTER()" instead.virtual void handleCmd_bad();virtual void handleCmd_notSupported();virtual void handleCmd_notFound();virtual void handleCmd_sessionNotFound();virtual void handleCmd_unsupportedTransport();// Support for optional RTSP-over-HTTP tunneling:virtual Boolean parseHTTPRequestString(char* resultCmdName, unsigned resultCmdNameMaxSize,char* urlSuffix, unsigned urlSuffixMaxSize,char* sessionCookie, unsigned sessionCookieMaxSize,char* acceptStr, unsigned acceptStrMaxSize);virtual void handleHTTPCmd_notSupported();virtual void handleHTTPCmd_notFound();virtual void handleHTTPCmd_OPTIONS();virtual void handleHTTPCmd_TunnelingGET(char const* sessionCookie);virtual Boolean handleHTTPCmd_TunnelingPOST(char const* sessionCookie, unsigned char const* extraData, unsigned extraDataSize);virtual void handleHTTPCmd_StreamingGET(char const* urlSuffix, char const* fullRequestStr);protected:void resetRequestBuffer();void closeSocketsRTSP();static void handleAlternativeRequestByte(void*, u_int8_t requestByte);void handleAlternativeRequestByte1(u_int8_t requestByte);Boolean authenticationOK(char const* cmdName, char const* urlSuffix, char const* fullRequestStr);void changeClientInputSocket(int newSocketNum, unsigned char const* extraData, unsigned extraDataSize);// used to implement RTSP-over-HTTP tunnelingstatic void continueHandlingREGISTER(ParamsForREGISTER* params);virtual void continueHandlingREGISTER1(ParamsForREGISTER* params);// Shortcuts for setting up a RTSP response (prior to sending it):void setRTSPResponse(char const* responseStr);void setRTSPResponse(char const* responseStr, u_int32_t sessionId);void setRTSPResponse(char const* responseStr, char const* contentStr);void setRTSPResponse(char const* responseStr, u_int32_t sessionId, char const* contentStr);RTSPServer& fOurRTSPServer; // same as ::fOurServerint& fClientInputSocket; // aliased to ::fOurSocketint fClientOutputSocket;Boolean fIsActive;unsigned char* fLastCRLF;unsigned fRecursionCount;char const* fCurrentCSeq;Authenticator fCurrentAuthenticator; // used if access control is neededchar* fOurSessionCookie; // used for optional RTSP-over-HTTP tunnelingunsigned fBase64RemainderCount; // used for optional RTSP-over-HTTP tunneling (possible values: 0,1,2,3)};RTSPServer::RTSPClientConnection 繼承自 GenericMediaServer::ClientConnection:
class GenericMediaServer: public Medium { . . . . . . public: // should be protected, but some old compilers complain otherwise// The state of a TCP connection used by a client:class ClientConnection {protected:ClientConnection(GenericMediaServer& ourServer, int clientSocket, struct sockaddr_in clientAddr);virtual ~ClientConnection();UsageEnvironment& envir() { return fOurServer.envir(); }void closeSockets();static void incomingRequestHandler(void*, int /*mask*/);void incomingRequestHandler();virtual void handleRequestBytes(int newBytesRead) = 0;void resetRequestBuffer();protected:friend class GenericMediaServer;friend class ClientSession;friend class RTSPServer; // needed to make some broken Windows compilers work; remove this in the future when we end support for WindowsGenericMediaServer& fOurServer;int fOurSocket;struct sockaddr_in fClientAddr;unsigned char fRequestBuffer[REQUEST_BUFFER_SIZE];unsigned char fResponseBuffer[RESPONSE_BUFFER_SIZE];unsigned fRequestBytesAlreadySeen, fRequestBufferBytesLeft;};從它們的定義,不難理解它們的職責主要在于處理網絡 I/O,處理 RTSP 請求,并建立會話。
再來看 RTSPServer::RTSPClientSession 的定義:
class RTSPServer: public GenericMediaServer { . . . . . .// The state of an individual client session (using one or more sequential TCP connections) handled by a RTSP server:class RTSPClientSession: public GenericMediaServer::ClientSession {protected:RTSPClientSession(RTSPServer& ourServer, u_int32_t sessionId);virtual ~RTSPClientSession();friend class RTSPServer;friend class RTSPClientConnection;// Make the handler functions for each command virtual, to allow subclasses to redefine them:virtual void handleCmd_SETUP(RTSPClientConnection* ourClientConnection,char const* urlPreSuffix, char const* urlSuffix, char const* fullRequestStr);virtual void handleCmd_withinSession(RTSPClientConnection* ourClientConnection,char const* cmdName,char const* urlPreSuffix, char const* urlSuffix,char const* fullRequestStr);virtual void handleCmd_TEARDOWN(RTSPClientConnection* ourClientConnection,ServerMediaSubsession* subsession);virtual void handleCmd_PLAY(RTSPClientConnection* ourClientConnection,ServerMediaSubsession* subsession, char const* fullRequestStr);virtual void handleCmd_PAUSE(RTSPClientConnection* ourClientConnection,ServerMediaSubsession* subsession);virtual void handleCmd_GET_PARAMETER(RTSPClientConnection* ourClientConnection,ServerMediaSubsession* subsession, char const* fullRequestStr);virtual void handleCmd_SET_PARAMETER(RTSPClientConnection* ourClientConnection,ServerMediaSubsession* subsession, char const* fullRequestStr);protected:void deleteStreamByTrack(unsigned trackNum);void reclaimStreamStates();Boolean isMulticast() const { return fIsMulticast; }// Shortcuts for setting up a RTSP response (prior to sending it):void setRTSPResponse(RTSPClientConnection* ourClientConnection, char const* responseStr) { ourClientConnection->setRTSPResponse(responseStr); }void setRTSPResponse(RTSPClientConnection* ourClientConnection, char const* responseStr, u_int32_t sessionId) { ourClientConnection->setRTSPResponse(responseStr, sessionId); }void setRTSPResponse(RTSPClientConnection* ourClientConnection, char const* responseStr, char const* contentStr) { ourClientConnection->setRTSPResponse(responseStr, contentStr); }void setRTSPResponse(RTSPClientConnection* ourClientConnection, char const* responseStr, u_int32_t sessionId, char const* contentStr) { ourClientConnection->setRTSPResponse(responseStr, sessionId, contentStr); }protected:RTSPServer& fOurRTSPServer; // same as ::fOurServerBoolean fIsMulticast, fStreamAfterSETUP;unsigned char fTCPStreamIdCount; // used for (optional) RTP/TCPBoolean usesTCPTransport() const { return fTCPStreamIdCount > 0; }unsigned fNumStreamStates;struct streamState {ServerMediaSubsession* subsession;int tcpSocketNum;void* streamToken;} * fStreamStates;};RTSPServer::RTSPClientSession 繼承自 GenericMediaServer::ClientSession:
// The state of an individual client session (using one or more sequential TCP connections) handled by a server:class ClientSession {protected:ClientSession(GenericMediaServer& ourServer, u_int32_t sessionId);virtual ~ClientSession();UsageEnvironment& envir() { return fOurServer.envir(); }void noteLiveness();static void noteClientLiveness(ClientSession* clientSession);static void livenessTimeoutTask(ClientSession* clientSession);protected:friend class GenericMediaServer;friend class ClientConnection;GenericMediaServer& fOurServer;u_int32_t fOurSessionId;ServerMediaSession* fOurServerMediaSession;TaskToken fLivenessCheckTask;};不難理解 RTSPServer::RTSPClientSession 用于封裝整個流媒體會話,處理那些要求流媒體會話已經建立的 RTSP 請求,如 PLAY 等。
具體的流媒體數據的交互,如音視頻文件/數據的解析,RTP/RTCP 數據的打包及收發等,則依賴于 ServerMediaSession 和 ServerMediaSubsession。
Done。
live555 源碼分析系列文章
live555 源碼分析:簡介
live555 源碼分析:基礎設施
live555 源碼分析:MediaSever
Wireshark 抓包分析 RTSP/RTP/RTCP 基本工作過程
live555 源碼分析:RTSPServer
live555 源碼分析:DESCRIBE 的處理
live555 源碼分析:SETUP 的處理
live555 源碼分析:PLAY 的處理
live555 源碼分析:RTSPServer 組件結構
總結
以上是生活随笔為你收集整理的live555 源码分析:RTSPServer 组件结构的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: live555 源码分析: PLAY 的
- 下一篇: live555 源码分析:ServerM