多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > 互聯網 > LIVE555研究之五:RTPServer(二)

LIVE555研究之五:RTPServer(二)

來源:程序員人生   發布時間:2014-10-12 08:37:45 閱讀次數:2161次

                                     LIVE555研究之五:RTPServer(二)

 

     接上文,main函數的幾行代碼創建了RTSPServer類的子類DynamicRTSPServer對象。RTPServer類是服務器類的基類,DynamicRTSPServer代表具體的服務器子類。我們今天介紹的服務器程序就是基于該類實現的。

     在創建DynamicRTSPServer時傳入了值為554的端口號。這是因為RTSP默認端口號為554,http默認使用80端口是一樣的。

      DynamicRTSPServer

        繼承關系:

                                             

                                                                                                                        

    Medium是很多類的基類。內部定義了指向環境類的引用和一個char類型媒體名稱。并定義了按照媒體名稱,查找對應媒體的成員函數lookupByName。由于MediaSinkMediaSouceMediaSessionRTSPClientRTPServer均繼承自該類,因此在Medium中定義了很多判斷該類是哪個媒體類型的函數:

virtual Boolean isSource() const; virtual Boolean isSink() const; virtual Boolean isRTCPInstance() const; virtual Boolean isRTSPClient() const; virtual Boolean isRTSPServer() const; virtual Boolean isMediaSession() const; virtual Boolean isServerMediaSession() const; virtual Boolean isDarwinInjector() const;

 

     Medium中的實現均是返回false。在對應的子類中均會重定義對應函數,并返回true

TaskToken fNextTask用來保存延遲任務的ID。保存的任務ID用于被重新調度,或者在該媒體對象被銷毀時從延遲隊列中取消調度。

       RTPServer類是服務器類的基類,代表了服務器對象。在整個服務器運行期間,該對象一直存在。

定義了以下成員變量:

 

HashTable* fServerMediaSessions; HashTable* fClientConnections; HashTable* fClientConnectionsForHTTPTunneling; HashTable* fClientSessions; HashTable* fPendingRegisterRequests;


       從其成員變量可以看到RTPServer中維護了ServerMediaSession對象、ClientConnectionClientSession對象的HashTable

       ServerMediaSessionSession對應服務器端一個媒體文件,當客戶端請求多個媒體文件時,RTPServer內會維護對應的多個ServerMediaSession對象。ServerMediaSession對象通過媒體文件名進行標識,如客戶端請求a.264文件,則服務器就會在保存ServerMediaSessionHashTable中搜索對應文件名為a.264ServerMediaSession。如未找到,則說明還未為該媒體文件創建對應的ServerMediaSession。并創建一個新的ServerMediaSession與媒體文件名關聯后添加到HashTable

       lookupServerMediaSession用于在map中搜索對應媒體文件名對應的ServerMediaSession

void addServerMediaSession(ServerMediaSession* serverMediaSession); virtual ServerMediaSession* lookupServerMediaSession(char const* streamName); void removeServerMediaSession(ServerMediaSession* serverMediaSession); void removeServerMediaSession(char const* streamName);


 

       以上三個成員函數分別用來添加、查詢和刪除對應ServerMediaSession項。

       removeServerMediaSession被調用后,在RTPServer中維護的fServerMediaSessionHashTable中,該ServerMediaSession會被刪除。但是對應的ServerMediaSession對象并不一定會被釋放。因為此時其他客戶端還有可能在使用該媒體文件。只有當其他客戶端都釋放了對該媒體文件的引用后,該對象才會被釋放。

 

       closeAllClientSessionsForServerMediaSession用于刪除所有客戶端對某一個媒體文件的引用。

       deleteServerMediaSession在從fServerMediaSession中刪除對應項目時同時也會刪除所有客戶端的引用,此后該對象的引用計數為0可以被安全釋放。

       removeServerMediaSession時會檢查引用計數,只有當引用計數為0時該對象才會被釋放。

if (serverMediaSession->referenceCount() == 0) //只有當引入計數為0時才會被釋放 { Medium::close(serverMediaSession); } else { serverMediaSession->deleteWhenUnreferenced() = True; }

ClientConnection對象

 

       ClientConnection對象定義在RTPServer內部,為其內部類。主要用于和客戶端的通信。當有新的客戶端連接到服務器時,會新建ClientConnection對象。其內部定義了發送、接收socket以及發送和接收緩沖區,并對客戶端的命令進行處理和回應。  

 void handleRequestBytes(int newBytesRead);

       用于處理客戶端命令,在對RTSP命令進行分析后,提取出各種信息,然后進行分流處理。

       對于OPTIONSDESCRIBE、命令不支持、命令有誤等其他錯誤命令的響應會直接在ClientConnection中進行處理。     而對于SETUPPLAYPAUSETERARDOWN等命令會傳遞到ClientSession中進行處理。

以下為分流代碼:

else if (strcmp(cmdName, "TEARDOWN") == 0 || strcmp(cmdName, "PLAY") == 0 || strcmp(cmdName, "PAUSE") == 0 || strcmp(cmdName, "GET_PARAMETER") == 0 || strcmp(cmdName, "SET_PARAMETER") == 0) { if (clientSession != NULL) { clientSession->handleCmd_withinSession(this, cmdName, urlPreSuffix, urlSuffix, (char const*)fRequestBuffer); } else { handleCmd_sessionNotFound(); }

       ClientSession對象會在客戶端請求SETUP命令時在ClientConnection中創建,并分配一個ClientSessionID。對于SETUP之前和對一些出錯處理命令會在ClientConnection中進行響應。

       ClientConnection維護了RTPServer的指針,可以在新建ClientSession對象后將其加入到RTPServer維護的fClientSessions中。

ClientSession中定義的成員:

RTSPServer& fOurServer; u_int32_t fOurSessionId; ServerMediaSession* fOurServerMediaSession;  

       ClientSession也維護了對RTPServer的引用。同時也保存了指向ServerMediaSession的指針。在對SETUP的響應中,有這樣一句話:

if (fOurServerMediaSession == NULL) { // We're accessing the "ServerMediaSession" for the first time. fOurServerMediaSession = sms; fOurServerMediaSession->incrementReferenceCount(); } else if (sms != fOurServerMediaSession) { // The client asked for a stream that's different from the one originally requested for this stream id. Bad request: ourClientConnection->handleCmd_bad(); break; }

     由此我們知道按照目前的實現,每個clientSession只能對應一個ServerMediaSession。即每個客戶端只能請求一個媒體文件,不能同時請求兩個媒體文件。如果需要同時支持多個媒體文件,就需要在ClientSession中維護一個ServerMediaSession集合。

 

ClientSessionnoteLiveness用于客戶端保活。其內部實現如下:
void RTSPServer::RTSPClientSession::noteLiveness()

{ if (fOurServer.fReclamationTestSeconds > 0) { envir().taskScheduler() .rescheduleDelayedTask(fLivenessCheckTask, fOurServer.fReclamationTestSeconds*1000000, (TaskFunc*)livenessTimeoutTask, this); } }

       上述代碼向調度器請求重新調度一個延遲任務,在fReclamationTestSeconds后會調用livenessTimeoutTask。其實現很簡單僅僅刪除自身。

void RTSPServer::RTSPClientSession ::livenessTimeoutTask(RTSPClientSession* clientSession) { delete clientSession; }

       當服務器收到對應客戶端的RR包時會調用noteLiveness,重新計時。

       fReclamationTestSecondsRTPServer構造時傳入,默認為65s。表示如65s內未收到客戶端RTCP包即認為客戶端已斷開。

       如果在fReclamationTestSeconds的時間內再次調用noteLiveness,則該延遲任務會被設置成新的時間,原來的調度不再起作用。

struct streamState { ServerMediaSubsession* subsession; void* streamToken; } * fStreamStates;

      fStreamStates指向一個動態分配的數組。fNumStreamStates表示該數組包含的元素個數。

     ServerMediaSession代表一個track(媒體流)。streamTokenvoid*類型的指針,但它指向StreamState類的對象。StreamState對象代表一個真正流動起來的數據流。這個流從XXXXFileSouce流向RTPSink

     可以看到一個ServerMediaSubSession對應一個StreamState。但ServerMediaSubSession對應一個靜態的流,可以被多個客戶端重用。如:多個客戶端可能會請求同一個媒體文件中的trackStreamState代表一個動態的流。

 

ServerMediaSession

 

         ServerMediaSession代表服務器端一個媒體文件。

其成員如下:

  

ServerMediaSubsession* fSubsessionsHead; ServerMediaSubsession* fSubsessionsTail; unsigned fSubsessionCounter; char* fStreamName; char* fInfoSDPString; char* fDescriptionSDPString; char* fMiscSDPLines; struct timeval fCreationTime; unsigned fReferenceCount; Boolean fDeleteWhenUnreferenced;

      可以看到其主要成員為fSubsessionsHeadfSubsessionsTail。代表該媒體文件中的多個媒體流trackfStreamName為該媒體文件名。fDescritionSDPString代表SDP字符串。用于在客戶端發送DESCRIBE命令時返回給客戶端。

       fReferenceCount為引用計數。當將fDeleteWhenUnreferenced設置為true,且引用計數為0時,ServerMediaSession會被釋放。該值在構造函數中默認賦值為false。即所有ServerMediaSession即使不存在被客戶端引用時,也不會被釋放。對于長時間運行的服務器程序將會出現內存消耗耗盡的情況。解決方案就是在構造時將fDeleteWhenUnreferenced的默認值賦值為true

       其他成員函數是用來操縱MediaSubSession

 

MediaSubSession

 

       如果一個媒體文件中既包含音頻流又包含視頻流,我們稱這個媒體文件中包含兩個track。每個track對應一個ServerMediaSubsession

ServerMediaSession* fParentSession; netAddressBits fServerAddressForSDP; portNumBits fPortNumForSDP; private: ServerMediaSubsession* fNext; unsigned fTrackNumber; // within an enclosing ServerMediaSession char const* fTrackId;

    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的究竟實現了什么功能。

 

OnDemandServerMediaSubsession& fMaster; Boolean fAreCurrentlyPlaying; unsigned fReferenceCount; Port fServerRTPPort, fServerRTCPPort; RTPSink* fRTPSink; BasicUDPSink* fUDPSink; float fStreamDuration; unsigned fTotalBW; RTCPInstance* fRTCPInstance; FramedSource* fMediaSource; float fStartNPT; Groupsock* fRTPgs; Groupsock* fRTCPgs;

      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與其他類間的關系不是那么緊密。

生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生

------分隔線----------------------------
分享到:
------分隔線----------------------------
為碼而活
積分:4237
15粉絲
7關注
欄目熱點
關閉
程序員人生
主站蜘蛛池模板: 亚洲一区二区黄色 | 伊人久久五月天 | 性一交一乱一伦 | bestpornvideos | 国产精品久久久久国产精品三级 | 国产精品一区二区国产 | 国产日韩高清一区二区三区 | 国产精品嫩草影院在线看 | 伊人一本之道 | 毛片无码国产 | 2020久久精品永久免费 | 高清视频在线观看 | 欧美 日韩 国产在线 | 午夜影院网站 | 亚洲乱乱 | 校园春色中文字幕 | 欧美三级视频在线播放 | 含羞草www在线视频免费 | 国产成人av在线 | 视频一区色眯眯视频在线 | 一级毛片毛片毛片毛毛片 | 亚洲伊人久久大香线蕉在观 | 一级特黄aa大片一又好看 | 99久久精品免费国产一区二区三区 | 欧美成人三级一区二区在线观看 | 国产女人久久精品 | 亚洲精品亚洲人成在线播放 | 一区二区精品 | 欧美人与物videos另 | 亚洲精品一区二区三区在 | 国产xxxxx在线观看 | 欧美亚洲福利 | 精品a级片 | 亚洲精品欧美精品中文字幕 | 久久国产欧美另类久久久 | 久久成人视 | 久久久久久国产精品免费 | 一级毛片一级毛片免费毛片 | 亚洲精品456在线观看 | 夜夜狠操| 日本a v 黄 |