LIVE555研究之五:RTPServer(二)
接上文,main函數的幾行代碼創建了RTSPServer類的子類DynamicRTSPServer對象。RTPServer類是服務器類的基類,DynamicRTSPServer代表具體的服務器子類。我們今天介紹的服務器程序就是基于該類實現的。
在創建DynamicRTSPServer時傳入了值為554的端口號。這是因為RTSP默認端口號為554,與http默認使用80端口是一樣的。
DynamicRTSPServer
繼承關系:
Medium是很多類的基類。內部定義了指向環境類的引用和一個char類型媒體名稱。并定義了按照媒體名稱,查找對應媒體的成員函數lookupByName。由于MediaSink、MediaSouce、MediaSession、RTSPClient、RTPServer均繼承自該類,因此在Medium中定義了很多判斷該類是哪個媒體類型的函數:
Medium中的實現均是返回false。在對應的子類中均會重定義對應函數,并返回true。
TaskToken fNextTask用來保存延遲任務的ID。保存的任務ID用于被重新調度,或者在該媒體對象被銷毀時從延遲隊列中取消調度。
RTPServer類是服務器類的基類,代表了服務器對象。在整個服務器運行期間,該對象一直存在。
定義了以下成員變量:
從其成員變量可以看到RTPServer中維護了ServerMediaSession對象、ClientConnection、ClientSession對象的HashTable。
ServerMediaSessionSession對應服務器端一個媒體文件,當客戶端請求多個媒體文件時,RTPServer內會維護對應的多個ServerMediaSession對象。ServerMediaSession對象通過媒體文件名進行標識,如客戶端請求a.264文件,則服務器就會在保存ServerMediaSession的HashTable中搜索對應文件名為a.264的ServerMediaSession。如未找到,則說明還未為該媒體文件創建對應的ServerMediaSession。并創建一個新的ServerMediaSession與媒體文件名關聯后添加到HashTable。
lookupServerMediaSession用于在map中搜索對應媒體文件名對應的ServerMediaSession。
以上三個成員函數分別用來添加、查詢和刪除對應ServerMediaSession項。
removeServerMediaSession被調用后,在RTPServer中維護的fServerMediaSession的HashTable中,該ServerMediaSession會被刪除。但是對應的ServerMediaSession對象并不一定會被釋放。因為此時其他客戶端還有可能在使用該媒體文件。只有當其他客戶端都釋放了對該媒體文件的引用后,該對象才會被釋放。
closeAllClientSessionsForServerMediaSession用于刪除所有客戶端對某一個媒體文件的引用。
deleteServerMediaSession在從fServerMediaSession中刪除對應項目時同時也會刪除所有客戶端的引用,此后該對象的引用計數為0可以被安全釋放。
在removeServerMediaSession時會檢查引用計數,只有當引用計數為0時該對象才會被釋放。
ClientConnection對象
ClientConnection對象定義在RTPServer內部,為其內部類。主要用于和客戶端的通信。當有新的客戶端連接到服務器時,會新建ClientConnection對象。其內部定義了發送、接收socket以及發送和接收緩沖區,并對客戶端的命令進行處理和回應。
void handleRequestBytes(int newBytesRead);
用于處理客戶端命令,在對RTSP命令進行分析后,提取出各種信息,然后進行分流處理。
對于OPTIONS、DESCRIBE、命令不支持、命令有誤等其他錯誤命令的響應會直接在ClientConnection中進行處理。 而對于SETUP、PLAY、PAUSE、TERARDOWN等命令會傳遞到ClientSession中進行處理。
以下為分流代碼:
ClientSession對象會在客戶端請求SETUP命令時在ClientConnection中創建,并分配一個ClientSessionID。對于SETUP之前和對一些出錯處理命令會在ClientConnection中進行響應。
ClientConnection維護了RTPServer的指針,可以在新建ClientSession對象后將其加入到RTPServer維護的fClientSessions中。
ClientSession中定義的成員:
ClientSession也維護了對RTPServer的引用。同時也保存了指向ServerMediaSession的指針。在對SETUP的響應中,有這樣一句話:
由此我們知道按照目前的實現,每個clientSession只能對應一個ServerMediaSession。即每個客戶端只能請求一個媒體文件,不能同時請求兩個媒體文件。如果需要同時支持多個媒體文件,就需要在ClientSession中維護一個ServerMediaSession集合。
ClientSession的noteLiveness用于客戶端保活。其內部實現如下:
void RTSPServer::RTSPClientSession::noteLiveness()
上述代碼向調度器請求重新調度一個延遲任務,在fReclamationTestSeconds后會調用livenessTimeoutTask。其實現很簡單僅僅刪除自身。
當服務器收到對應客戶端的RR包時會調用noteLiveness,重新計時。
fReclamationTestSeconds在RTPServer構造時傳入,默認為65s。表示如65s內未收到客戶端RTCP包即認為客戶端已斷開。
如果在fReclamationTestSeconds的時間內再次調用noteLiveness,則該延遲任務會被設置成新的時間,原來的調度不再起作用。
fStreamStates指向一個動態分配的數組。fNumStreamStates表示該數組包含的元素個數。
ServerMediaSession代表一個track(媒體流)。streamToken是void*類型的指針,但它指向StreamState類的對象。StreamState對象代表一個真正流動起來的數據流。這個流從XXXXFileSouce流向RTPSink。
可以看到一個ServerMediaSubSession對應一個StreamState。但ServerMediaSubSession對應一個靜態的流,可以被多個客戶端重用。如:多個客戶端可能會請求同一個媒體文件中的track。StreamState代表一個動態的流。
ServerMediaSession
ServerMediaSession代表服務器端一個媒體文件。
其成員如下:
可以看到其主要成員為fSubsessionsHead、fSubsessionsTail。代表該媒體文件中的多個媒體流track。fStreamName為該媒體文件名。fDescritionSDPString代表SDP字符串。用于在客戶端發送DESCRIBE命令時返回給客戶端。
fReferenceCount為引用計數。當將fDeleteWhenUnreferenced設置為true,且引用計數為0時,ServerMediaSession會被釋放。該值在構造函數中默認賦值為false。即所有ServerMediaSession即使不存在被客戶端引用時,也不會被釋放。對于長時間運行的服務器程序將會出現內存消耗耗盡的情況。解決方案就是在構造時將fDeleteWhenUnreferenced的默認值賦值為true。
其他成員函數是用來操縱MediaSubSession。
MediaSubSession
如果一個媒體文件中既包含音頻流又包含視頻流,我們稱這個媒體文件中包含兩個track。每個track對應一個ServerMediaSubsession。
fParentSession指向該MediaSubSession所屬的ServerMediaSession。
fNext指向下一個同屬于一個ServerMediaSession的ServerMediaSubsession。如果只包含一個媒體流,則fNext指針為NULL。
fTrackNumber為track號。在客戶端發送DESCRIBE命令時,服務器端會為每個媒體流分配一個TrackID。
fTrackId 為字符串指針,該字符串由”track”和fTrackNumber拼接而成。如track1、track2。
ServerMediaSubsession中僅僅定義了空的接口,具體實現均放在其子類。
OnDemandServerMediaSubsession
HashTable* fDestinationsHashTable; 存儲sessionID和Destinations的映射。
Destinations為目的地址。每個ClientSession在HashTable中都有與自己對應的項。
Destinations可以維護一對RTP和RTCP的端口和地址信息。
StreamState
前面說過StreamState代表一個真正流動的流,現在讓我們看下StreamState的究竟實現了什么功能。
fMaster為對OnDemandServerMediaSubsession或其子類的引用。
fReferenceCount為引用計數。
fServerRTPPort為RTP端口
fServerRTCPPort為RTCP端口
fRTPSink抽象Sink類。
fMediaSource為Souce基類。
可以看到StreamState既維護了Sink,又維護了Souce。其實在StreamState
GroupSock主要用于處理組播,但也可以處理單播。
Groupsock* fRTPgs和 Groupsock* fRTCPgs為RTP和RTCP的地址,用于向RTP和RTCP端口發送數據。
RTCPInstance
RTCPInsance是對RTCP通信的封裝。RTCP的功能是統計包的收發,為流量統計提供依據。由于其封裝的比較完整,因此RTCPInstance與其他類間的關系不是那么緊密。
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈