live555做流媒體服務器時解決rtp over udp模式下, 客戶端沒有發送teardown時直接關閉導致RTSPServer端沒有即時關閉流的問題解決方法

在我們使用live555作爲RTSP服務器時,客戶端在rtp over udp模式下, rtsp客戶端沒有發送teardown而直接斷開連接時需要等待65秒纔回調關閉的問題。

分析問題

在RTSPClientConnection中沒有保存相應的session值, 所以在RTSPClientConnection斷開時, 並沒有刪除相應的RTSPClientSession;

解決問題

在RTSPClientConnection的聲明中,增加以下定義;

		char fClientSessionIdStr[16];	//for rtp over udp
		
		GenericMediaServer.hh  增加createNewClientSessionWithId的參數char *pSessionIdStr
		ClientSession* createNewClientSessionWithId(UsageEnvironment	*pEnv, char *pSessionIdStr);
		
		GenericMediaServer::ClientSession* GenericMediaServer::createNewClientSessionWithId(UsageEnvironment	*_pEnv, char *pSessionIdStr) {
		  u_int32_t sessionId;
		  char sessionIdStr[16] = {0};

		  // Choose a random (unused) 32-bit integer for the session id
		  // (it will be encoded as a 8-digit hex number).  (We avoid choosing session id 0,
		  // because that has a special use by some servers.)
		  do {
		    sessionId = (u_int32_t)our_random32();
		    snprintf(sessionIdStr, sizeof sessionIdStr, "%08X", sessionId);
		  } while (sessionId == 0 || lookupClientSession(sessionIdStr) != NULL);

		  ClientSession* clientSession = createNewClientSession(sessionId, _pEnv);
		  if (clientSession != NULL) fClientSessions->Add(sessionIdStr, clientSession);

		  if (NULL != pSessionIdStr)	strcpy(pSessionIdStr, sessionIdStr);		//此處返回生成的sessionId, 後續要根據該值找到對應的ClientSession

		  return clientSession;
		}		
		
		
		
		void RTSPServer::RTSPClientConnection::handleRequestBytes(int newBytesRead, UsageEnvironment *pEnv) {

			//找到以下代碼		
		  if (authenticationOK("SETUP", urlTotalSuffix, (char const*)fRequestBuffer)) {
			  memset(fClientSessionIdStr, 0x00, sizeof(fClientSessionIdStr));
		    clientSession
		      = (RTSPServer::RTSPClientSession*)fOurRTSPServer.createNewClientSessionWithId(pEnv, fClientSessionIdStr);		//此處記錄ClientSession的sessionId
		  }		
		
		}

此時,在RTSPClientConnection中已經保存了對應的SessionId, 在客戶端斷開連接時, 可以根據該SessionId, 找到相應的ClientSession, 然後刪除;


		void RTSPServer::stopTCPStreamingOnSocket(UsageEnvironment *pEnv, int socketNum, int *clientTrackNum, char *clientSessionIdStr){
		  // Close any stream that is streaming over "socketNum" (using RTP/RTCP-over-TCP streaming):

			RTSPClientSession	*pClientSession = NULL;

			LockClientConnection();
			do
			{
			  streamingOverTCPRecord* sotcp
				= (streamingOverTCPRecord*)fTCPStreamingDatabase->Lookup((char const*)socketNum);
			  if (sotcp != NULL) {		//rtp over tcp
				do {
				  RTSPClientSession* clientSession
				= (RTSPServer::RTSPClientSession*)lookupClientSession(sotcp->fSessionId);
				  if (clientSession != NULL) {
					  //clientSession->SetAssignSink(assignSink);
				clientSession->deleteStreamByTrack(pEnv, sotcp->fTrackNum, False, clientTrackNum);
				  }

				  streamingOverTCPRecord* sotcpNext = sotcp->fNext;
				  sotcp->fNext = NULL;
				  delete sotcp;
				  sotcp = sotcpNext;
				} while (sotcp != NULL);
				fTCPStreamingDatabase->Remove((char const*)socketNum);
			  }
			  else if ( (clientTrackNum) && (*clientTrackNum==0))		//rtp over udp
			  {
				  pClientSession = (RTSPServer::RTSPClientSession*)lookupClientSession(clientSessionIdStr);
			  }
			}while (0);

			UnlockClientConnection();

			if (pClientSession != NULL) 		//pClientSession不爲空, 說明爲rtp over udp
			{
				delete pClientSession;
			}

		}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章