在我们使用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;
}
}