前面幾篇文章分析了 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; // forward
class 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 server
virtual void handleCmd_SET_PARAMETER(char const* fullRequestStr); // when operating on the entire server
virtual 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 tunneling
static 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 ::fOurServer
int& fClientInputSocket; // aliased to ::fOurSocket
int fClientOutputSocket;
Boolean fIsActive;
unsigned char* fLastCRLF;
unsigned fRecursionCount;
char const* fCurrentCSeq;
Authenticator fCurrentAuthenticator; // used if access control is needed
char* fOurSessionCookie; // used for optional RTSP-over-HTTP tunneling
unsigned 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 Windows
GenericMediaServer& 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 ::fOurServer
Boolean fIsMulticast, fStreamAfterSETUP;
unsigned char fTCPStreamIdCount; // used for (optional) RTP/TCP
Boolean 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 組件結構