(轉)live555 RTSP Server RTP over TCP BUG


最近碰到一個非常棘手的問題,NVR通過ONVIF協議接入IPC進行錄像,在錄像時,會發現其中有個別IPC會出現錄像斷斷續續的情況。這種情況很難復現,但是這種情況一旦出現,整個過程會一直持續很長時間,一般是直到重啟RTSP Server。

通過苦逼型的大規模測試發現: 
1、IPC與NVR之間是通過RTP over TCP的方式傳輸數據(這個測試結果很簡單就可以知道); 
2、開啟1個客戶端(通過RTP over TCP傳輸數據),打開rtsp流后,使用任務管理器強制結束。緊接着馬上再開1個客戶端,打開rtsp流,稍等一會兒(1分鍾左右),后面開啟的這個流居然自動斷開了。這是一個必現的bug。(這里測試時,客戶端可使用VLC,不過VLC默認情況下是使用RTP over UDP的方式傳輸數據。要使用 over TCP方式接收數據,需要通過以下設置: “工具”->“首選項”,打開首選項對話框后,“顯示設置”處點擊“全部”單選按鈕,在左側樹形菜單依次展開:“輸入/編解碼器”->“去復用器”->“RTP/RTSP”,選中“使用RTP over RTSP(TCP)”);

通過調試發現: 
1、RTSPServer::createNew()的參數里面有個reclamationTestSeconds參數,該參數默認值為65; 
2、RTSPServer::createNewClientSession創建一個RTSPClientSession實例時,RTSPClientSession構造函數會調用noteLiveness,noteLiveness會設置一個延時任務,該任務的延時時間即為1中的reclamationTestSeconds(其值為秒,需要轉換為微秒,回調為livenessTimeoutTask)。noteLiveness除了在構造的時候調用,在RTSP SERVER接收到一個RR數據包后,也會調用(RR其實也用作了一種心跳包了);
3、RTSPServer::incomingConnectionHandler()函數在異常結束上一個客戶端后,再打開一個客戶端打開rtsp流時,函數中accept返回的socket的值和上一個客戶端的socket句柄值是相同的(概率在50%以上,如果這里返回的socket句柄不同,這個bug就不會復現了);

通過以上3條,如果你讀過live555的代碼,應該知道是怎么回事了。上面2中設置的延時任務的回調函數livenessTimeoutTask,只干了一件事件,就是delete掉RTSPServer::createNewClientSession創建的實例。查看RTSPClientSession的析構函數,發現其居然把RTPInterface::fTCPStreams鏈表中對應的節點給刪掉了。而RTP和RTCP包是通過RTSPServer::sendPacket發送到各個客戶端的,在發送的時候,就是直接對RTPInterface::fTCPStreams保存的地址(即socket句柄)進行發送。如果RTPInterface::fTCPStreams中的socket清除了,客戶端自然不會再接收到數據,出現斷線已經是必然了。至此,斷線的原因終於明了:即異常結束掉一個客戶端,在65秒內(默認值為65),再開啟一個客戶端打開流,第二次打開的這條流會在65秒內必然斷開,如果客戶端有斷線自動重連的功能,那么,斷斷續續的情況就出現了。

通過測試還發現,通過RTP over UDP的方式接收數據時,異常結束客戶端,RTSP Server居然會接收到一條TEARDOWN消息,而在TEARDOWN消息的處理過程中,會清理掉client session和RTSP鏈接,即使用RTP OVER UDP的方式傳輸數據時,異常結束客戶端,並不會出現上述bug,這個讓我困惑不少,如果哪位知道,請告訴我原因。

其實解決這個問題,只需要注釋掉livenessTimeoutTask中的delete語句就行了,不過這不是最終解決方案,因為會造成內存泄漏,最好的方式是使用SESSION ID和目標地址進行關聯,在調用StreamState::endPlaying刪除目的地址時,如果SESSION ID不對應,不從鏈表中清除掉對應的節點就行了。

轉自:http://m.blog.csdn.net/blog/zxwangyun/40541023


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM