/****************************************************************************** * FILE: RtspClientSession.cpp * Description: * Implement for CRtspClientSession class. * * Modified Code History * Mark Date By Modification Reason ******************************************************************************* * 01 2013/5/28 songxw Initial creation. ******************************************************************************/ #include "RtspClientSession.h" #include "rtppacket.h" #define A_SESSION_OCCUPY_MEDIA_PORT 2 CRtspClientSession::CRtspClientSession() { //Channel = Chan; bAudio = false; SendKeepAliveTime = GetClockTime(); // ÓÃʱ¼äºÍpid×÷ÎªËæ»úÊýÖÖ×Ó, ±ÜÃâ¶à½ø³ÌͬʱִÐлòµ¥½ø³Ì¶à´ÎÖ´ÐÐÊ±Ëæ»úÊýÏàͬµÄÎÊÌâ¡£ srand( (UINT32)time(NULL) + (UINT32)getpid() ); int RandSeed = rand() % ( (RtspEndPort - RtspBeginPort) / A_SESSION_OCCUPY_MEDIA_PORT - 1); RtspCurrentPort = RtspBeginPort + RandSeed * A_SESSION_OCCUPY_MEDIA_PORT; pTcpTransport = NULL; pRtspProt = new CRtspProtocol( (CRtspProtocolResponse*)this); if (NULL == pRtspProt) { printf("pRtspProt is null pointer at %s:%d!", __FILE__, __LINE__); exit(1); } m_bSupportsGetParam = false; m_pTcpStreamTrans = NULL; m_pUdpStreamTrans = NULL; m_bExitFlag = false; } CRtspClientSession::~CRtspClientSession(void) { SAFE_DELETE(m_pUdpStreamTrans); SAFE_DELETE(m_pTcpStreamTrans); SAFE_DELETE(pTcpTransport); SAFE_DELETE(pRtspProt); } /* Initialization static variables */ UINT16 CRtspClientSession::RtspBeginPort = RTSP_CLIENT_SESSION_BEGIN_PORT; UINT16 CRtspClientSession::RtspEndPort = RTSP_CLIENT_SESSION_END_PORT; UINT16 CRtspClientSession::RtspCurrentPort = RtspBeginPort; /******************************************************************************* * Function: * Find a idle port and allocate to occupy. *******************************************************************************/ bool CRtspClientSession::AllocatePortID(UINT16 &PId) { if(RtspBeginPort > RtspEndPort) { RtspEndPort = 65535; } for (int i=RtspBeginPort; i= RtspEndPort) RtspCurrentPort = RtspBeginPort; //ÅжÏÊÓÆµºÍÒôƵ¶Ë¿ÚÊÇ·ñÕ¼Óã¬Ã»ÓÐÅжÏRTCP¶Ë¿Ú¡£ if ( !PortIsOccupied(PId) && !PortIsOccupied(PId+2) ) { // DBGPrint(M_RtspClientLib, BREAK_LEVEL, "%s: port<%d> success.", __FUNCTION__, PId); return true; } } printf("Allocate port fail!BeginPort<%d> - EndPort<%d> !", RtspBeginPort, RtspEndPort); return false; } /******************************************************************************* * Function: * »ñÈ¡±¾µØipµØÖ· *******************************************************************************/ int CRtspClientSession::GetLocalIP(char *address, int size) { unsigned int len; int sock_rt, on = 1; struct sockaddr_in iface_out; struct sockaddr_in remote; memset(&remote, 0, sizeof(struct sockaddr_in)); remote.sin_family = AF_INET; remote.sin_addr.s_addr = inet_addr("217.12.3.11"); remote.sin_port = htons(11111); memset(&iface_out, 0, sizeof(iface_out)); sock_rt = socket(AF_INET, SOCK_DGRAM, 0); if (setsockopt(sock_rt, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) == -1) { perror("DEBUG: [get_output_if] setsockopt(SOL_SOCKET, SO_BROADCAST"); close(sock_rt); snprintf(address, size, "127.0.0.1"); return -10; } if (connect (sock_rt, (struct sockaddr *) &remote, sizeof(struct sockaddr_in)) == -1) { perror("DEBUG: [get_output_if] connect"); close(sock_rt); snprintf(address, size, "127.0.0.1"); return -10; } len = sizeof(iface_out); if (getsockname(sock_rt, (struct sockaddr *) &iface_out, &len) == -1) { perror("DEBUG: [get_output_if] getsockname"); close(sock_rt); snprintf(address, size, "127.0.0.1"); return -10; } close(sock_rt); if (iface_out.sin_addr.s_addr == 0) { /* what is this case?? */ snprintf(address, size, "127.0.0.1"); return -10; } strncpy(address, inet_ntoa(iface_out.sin_addr), size - 1); return 0; } /******************************************************************************* * Function: * Check the port busy or no. *******************************************************************************/ bool CRtspClientSession::PortIsOccupied(const UINT16 PId) { char pIpStr[24] = {0}; GetLocalIP(pIpStr, 24); //Create the UDP socket int SockFd = socket(AF_INET, SOCK_DGRAM, 0/*IPPROTO_UDP*/); if (SockFd < 0) { DBGPrint(M_RtspClientLib, ERROR_LEVEL, "%s:PortIsOccupied create socket failed!", __FUNCTION__); perror("RtspSessMgr socket"); return true; } struct sockaddr_in addr; //Init bind address bzero(&addr, sizeof(struct sockaddr_in) ); addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr(pIpStr); addr.sin_port = htons(PId); //Bind the socket to special port if (bind(SockFd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in) ) == -1) { DBGPrint(M_RtspClientLib, ERROR_LEVEL, "%s:PortIsOccupied bind socket failed!", __FUNCTION__); close(SockFd); //BugFix at 2008-7-16 perror("Rtsp Client Session bind"); return true; } close(SockFd); return false; } /******************************************************************************* * Function: * Digest MD5 authorization validate process. RTSP¿Í»§¶ËÓ¦¸ÃʹÓÃusername + password²¢¼ÆËãresponseÈçÏÂ: (1)µ±passwordΪMD5±àÂë,Ôò response = md5(password:nonce:md5(public_method:url)); (2)µ±passwordΪANSI×Ö·û´®,Ôò response= md5(md5(username:realm:password):nonce:md5(public_method:url)); ¿Í»§¶ËÔÚÿ´Î·¢Æð²»Í¬µÄÇëÇó·½·¨Ê±¶¼ÐèÒª¼ÆËãresponse×ֶΣ¬ ͬÑùÔÚ·þÎñÆ÷¶ËУÑéʱҲĬÈϲÉȡͬÑùµÄ¼ÆËã·½·¨¡£ *******************************************************************************/ char* CRtspClientSession::createAuthenticatorString(char *cmd, char *url) { if (m_Authenticator.realm() != NULL && m_Authenticator.username() != NULL && m_Authenticator.password() != NULL) { // We have a filled-in authenticator, so use it: char* authenticatorStr; if (m_Authenticator.nonce() != NULL) { // Digest authentication char const* const authFmt = "Digest username=\"%s\", realm=\"%s\", " "nonce=\"%s\", uri=\"%s\", response=\"%s\""; char const* response = m_Authenticator.computeDigestResponse(cmd, url); unsigned authBufSize = strlen(authFmt) + strlen(m_Authenticator.username()) + strlen(m_Authenticator.realm()) + strlen(m_Authenticator.nonce()) + strlen(url) + strlen(response); authenticatorStr = new char[authBufSize]; sprintf(authenticatorStr, authFmt, m_Authenticator.username(), m_Authenticator.realm(), m_Authenticator.nonce(), url, response); m_Authenticator.reclaimDigestResponse(response); } else { // Basic authentication char const* const authFmt = "Basic %s"; unsigned usernamePasswordLength = strlen(m_Authenticator.username()) + 1 + strlen(m_Authenticator.password()); char* usernamePassword = new char[usernamePasswordLength+1]; sprintf(usernamePassword, "%s:%s", m_Authenticator.username(), m_Authenticator.password()); char* response = base64MyEncode(usernamePassword, usernamePasswordLength); unsigned const authBufSize = strlen(authFmt) + strlen(response) + 1; authenticatorStr = new char[authBufSize]; sprintf(authenticatorStr, authFmt, response); delete[] response; delete[] usernamePassword; } return authenticatorStr; } // We don't have a (filled-in) authenticator. return NULL; } #if 0 void* CRtspClientSession::Thread() { ThreadStarted(); while(!m_bExitFlag) { int now = GetClockTime(); //½ÓÊÕµ½ÂëÁ÷ºó £¬Ã¿¸ô60s ·¢Ëͱ¥ºÍ°ü if(now - SendKeepAliveTime >= RTSP_KEEPALIVE_TIME) { KeepAliveSession(); SendKeepAliveTime = now; } usleep(1000*1000); } printf("%s: Stream Thread Exit %p, Jstream::ThreadQuit Sucess!!!", __FUNCTION__, this); return NULL; } void CRtspClientSession::ThreadQuit(void) { m_bExitFlag = true; int times = 5; while ( JThread::IsRunning() && times-- > 0 ) { usleep(100000); } if (times < 0) { printf("Jstream::ThreadQuit Fail.\n"); } } #endif /******************************************************************************* * Function: * Do OPTIONS request and Driver context. *******************************************************************************/ bool CRtspClientSession::KeepAliveSession(void) { int nRet = -1; if (m_bSupportsGetParam == true) { nRet = GetParam(SessionID); if (nRet < 0) { printf("KeepAliveSession GetParam failed! url<%s> <%s>", (char*)(CPCHAR)CnxData.StrUrl, m_RtspUrl); return false; } } else { nRet = Options(m_RtspUrl); if (nRet < 0) { printf("KeepAliveSession Options failed! url<%s> <%s>", (char*)(CPCHAR)CnxData.StrUrl, m_RtspUrl); return false; } } return true; } /******************************************************************************* * Function: * Do OPTIONS request and Driver context. *******************************************************************************/ int CRtspClientSession::Options(const char* pUrl) { //Check input parameters exception if (NULL == pUrl) { DBGPrint(M_RtspClientLib, ERROR_LEVEL, "%s: pUrl is null pointer!", __FUNCTION__); return -1; } CnxData.StrUrl = pUrl; CRtspRequestMsg ReqMsg; ReqMsg.SetVerb(VERB_OPTIONS); ReqMsg.SetUrl(CnxData.StrUrl); ReqMsg.SetHdr("User-Agent", RTSP_USER_AGENT); if (m_bSetAuth == true) { char* authenticatorStr = createAuthenticatorString((char *)ReqMsg.GetVerbStr(), m_RtspUrl); if (authenticatorStr != NULL) { ReqMsg.SetHdr("Authorization", authenticatorStr); delete[] authenticatorStr; } } return DoWork(ReqMsg); } /******************************************************************************* * Function: * Do DESCRIBE request and Driver context. *******************************************************************************/ int CRtspClientSession::Describe(const char* pUrl, bool bAuth) { //Check input parameters exception if (NULL == pUrl) { DBGPrint(M_RtspClientLib, ERROR_LEVEL, "%s: pUrl is null pointer!", __FUNCTION__); return -1; } CnxData.StrUrl = pUrl; CRtspRequestMsg ReqMsg; ReqMsg.SetVerb(VERB_DESCRIBE); ReqMsg.SetUrl(CnxData.StrUrl); if (bAuth == true) { char* authenticatorStr = createAuthenticatorString((char *)ReqMsg.GetVerbStr(), m_RtspUrl); if (authenticatorStr != NULL) { ReqMsg.SetHdr("Authorization", authenticatorStr); delete[] authenticatorStr; } } ReqMsg.SetHdr("User-Agent", RTSP_USER_AGENT); ReqMsg.SetHdr("Accept", "application/sdp"); return DoWork(ReqMsg); } /******************************************************************************* * Function: * Do SETUP request and Driver context. *******************************************************************************/ int CRtspClientSession::Setup(const CString& SessionID, const CString StreamId, bool bCreateTcpSvr) { char ClipBuf[HTTP_URL_MAX_LEN+1] = {0}; CRtspRequestMsg ReqMsg; ReqMsg.SetVerb(VERB_SETUP); //Set stream id if ( !StreamId.IsEmpty() ) { static CString RtspHeader("rtsp://"); if(StreamId.CompareNumNoCase(RtspHeader, RtspHeader.GetLength()) == 0) { ReqMsg.SetUrl(StreamId); } else { /* rtsp://192.168.1.10:554/h264/streamid=0 */ snprintf(ClipBuf, sizeof(ClipBuf), "%s/%s", (char*)(CPCHAR)CnxData.StrUrl, (char*)(CPCHAR)StreamId); //snprintf(ClipBuf, sizeof(ClipBuf), "rtsp://192.168.12.16/MediaInput/h264/trackID=1"); CString NewStrUrl(ClipBuf); ReqMsg.SetUrl(NewStrUrl); } } else { ReqMsg.SetUrl(CnxData.StrUrl); } if (m_bSetAuth == true) { char* authenticatorStr = createAuthenticatorString((char *)ReqMsg.GetVerbStr(), m_RtspUrl); if (authenticatorStr != NULL) { ReqMsg.SetHdr("Authorization", authenticatorStr); delete[] authenticatorStr; } } printf("#########Setup##########Rtsp Session Url<%s> \n", (char*)ReqMsg.GetUrl()); //Set Session header if ( !SessionID.IsEmpty() ) { ReqMsg.SetHdr("Session", SessionID); } //Set Transport header if (CRtspClientSession::AllocatePortID(CnxData.ClientPort) ) { snprintf(ClipBuf, sizeof(ClipBuf), "RTP/AVP;unicast;client_port=%d-%d", CnxData.ClientPort, CnxData.ClientPort + 1); ReqMsg.SetHdr("Transport", ClipBuf); //Ìáǰ´´½¨tcpserver if (bCreateTcpSvr == true && m_pTcpStreamTrans != NULL) { m_pTcpStreamTrans->CreateTcpServer(CnxData.ClientPort); if (m_pTcpStreamTrans->IsRunning() == false) { m_pTcpStreamTrans->Start(); } } else if (m_pUdpStreamTrans != NULL) { printf("\n\n>>>>>>>>>>>>>>>>>>>>>>>>>>m_pUdpStreamTrans create rtp port:%d sucess!!!\n\n", CnxData.ClientPort); //ÉèÖòÎÊý m_pUdpStreamTrans->SetStreamTransParam(E_STREAM_TRANS_UDP, CnxData.strServerIp.c_str(), CnxData.ServerPort, CnxData.strClientIp.c_str(), CnxData.ClientPort); if (m_pUdpStreamTrans->InitRtp() < 0) { return -1; } } } else { return -1; } ReqMsg.SetHdr("User-Agent", RTSP_USER_AGENT); int iRet = DoWork(ReqMsg); if ( (-1 == iRet) || CnxData.SessionID.IsEmpty() || (0 == CnxData.ServerPort) || (0 == CnxData.ClientPort) ) return -1; return 0; } /******************************************************************************* * Function: * Do PLAY request and Driver context. *******************************************************************************/ int CRtspClientSession::Play(const CString& SessionID, int ctrltype, double ctrlparam) { CRtspRequestMsg ReqMsg; ReqMsg.SetVerb(VERB_PLAY); ReqMsg.SetUrl(CnxData.StrUrl); if (m_bSetAuth == true) { char* authenticatorStr = createAuthenticatorString((char *)ReqMsg.GetVerbStr(), m_RtspUrl); if (authenticatorStr != NULL) { ReqMsg.SetHdr("Authorization", authenticatorStr); delete[] authenticatorStr; } } if ( !SessionID.IsEmpty() ) { ReqMsg.SetHdr("Session", SessionID); } char param[64] = {0}; switch(ctrltype) { case HIS_VIDEO_CTRL_PLAY: { ReqMsg.SetHdr("Range", "npt=0-"); } break; case HIS_VIDEO_CTRL_FAST: { double dSpeed = 1.0; if (ctrlparam <= 0) { dSpeed = 1.0; } else if (ctrlparam >= 32) { dSpeed = 32.0; } else { dSpeed = (double)ctrlparam; } sprintf(param, "%lf", dSpeed); ReqMsg.SetHdr("Scale", param); } break; case HIS_VIDEO_CTRL_SLOW: { double dSpeed = 1.0; if (ctrlparam <= 0) { dSpeed = 1.0; } else if (ctrlparam >= 32) { dSpeed = 1/32.0; } else { dSpeed = 1/(double)ctrlparam; } sprintf(param, "%lf", dSpeed); ReqMsg.SetHdr("Scale", param); } break; case HIS_VIDEO_CTRL_JUMP: { sprintf(param, "npt=%.3f-", ctrlparam); ReqMsg.SetHdr("Range", param); } break; default: break; } return DoWork(ReqMsg); } /******************************************************************************* * Function: * Do PAUSE request and Driver context. *******************************************************************************/ int CRtspClientSession::Pause(const CString& SessionID) { CRtspRequestMsg ReqMsg; ReqMsg.SetVerb(VERB_PAUSE); ReqMsg.SetUrl(CnxData.StrUrl); if (m_bSetAuth == true) { char* authenticatorStr = createAuthenticatorString((char *)ReqMsg.GetVerbStr(), m_RtspUrl); if (authenticatorStr != NULL) { ReqMsg.SetHdr("Authorization", authenticatorStr); delete[] authenticatorStr; } } if ( !SessionID.IsEmpty() ) { ReqMsg.SetHdr("Session", SessionID); } return DoWork(ReqMsg); } /******************************************************************************* * Function: * Do TEARDOWN request and Driver context. *******************************************************************************/ int CRtspClientSession::Teardown(const CString& SessionID, const CString StreamId) { if (SessionID.IsEmpty()) { printf("%s:seesion id is null!\n", __FUNCTION__); return -1; } char ClipBuf[128+1] = {0}; CRtspRequestMsg ReqMsg; ReqMsg.SetVerb(VERB_TEARDOWN); //Set stream id if ( !StreamId.IsEmpty() ) { /* rtsp://192.168.1.10:554/h264/streamid=0 */ snprintf(ClipBuf, sizeof(ClipBuf), "%s/%s", (char*)(CPCHAR)CnxData.StrUrl, (char*)(CPCHAR)StreamId); CString NewStrUrl(ClipBuf); ReqMsg.SetUrl(NewStrUrl); } else { ReqMsg.SetUrl(CnxData.StrUrl); } if (m_bSetAuth == true) { char* authenticatorStr = createAuthenticatorString((char *)ReqMsg.GetVerbStr(), m_RtspUrl); if (authenticatorStr != NULL) { ReqMsg.SetHdr("Authorization", authenticatorStr); delete[] authenticatorStr; } } if ( !SessionID.IsEmpty() ) { ReqMsg.SetHdr("Session", SessionID); } return DoWork(ReqMsg); } /******************************************************************************* * Function: * Do GET_PARAMETER request and Driver context. *******************************************************************************/ int CRtspClientSession::GetParam(const CString& SessionID) { CRtspRequestMsg ReqMsg; ReqMsg.SetVerb(VERB_GETPARAM); ReqMsg.SetUrl(CnxData.StrUrl); if (m_bSetAuth == true) { char* authenticatorStr = createAuthenticatorString((char *)ReqMsg.GetVerbStr(), m_RtspUrl); if (authenticatorStr != NULL) { ReqMsg.SetHdr("Authorization", authenticatorStr); delete[] authenticatorStr; } } if ( !SessionID.IsEmpty() ) { ReqMsg.SetHdr("Session", SessionID); } return DoWork(ReqMsg); } //////////////////////////////////////////////////// Response //////////////////////////////////////////////////////// /******************************************************************************* * Function: * ´¦ÀíOPTIONSÏûÏ¢µÄ»ØÓ¦¡£ *******************************************************************************/ void CRtspClientSession::OnOptionsResponse(CRtspResponseMsg* pMsg) { if (strstr((CPCHAR)pMsg->GetHdr("Public"), "GET_PARAMETER") != NULL) { m_bSupportsGetParam = true; } } /******************************************************************************* * Function: * ´¦ÀíDESCRIBEÏûÏ¢µÄ»ØÓ¦¡£ *******************************************************************************/ void CRtspClientSession::OnDescribeResponse(CRtspResponseMsg* pMsg) { //Check input parameters exception if (NULL == pMsg) { printf("%s: pMsg is null pointer!\n", __FUNCTION__); return; } //ÈÏÖ¤ if (pMsg->GetStatusCode() == 401) { m_Authenticator.setRealmAndNonce(pMsg->mUserData.AuthRealm, pMsg->mUserData.AuthNonce); printf("%s:set auth realm:%s nonce:%s \n", __FUNCTION__, pMsg->mUserData.AuthRealm, pMsg->mUserData.AuthNonce); return; } char *pSdpStr = (char*)pMsg->GetBuf(); if (NULL == pSdpStr) { printf("%s: pSdpStr is null pointer!\n", __FUNCTION__); return; } pSdpStr[pMsg->GetBufLen()] = 0; //½âÎöÓîÊÓSDPÐÅÏ¢ //ÔÝʱδ×öÈÏ֤ģ¿é£¬ºóÐøÌí¼Ó //-------------------------------------------- char *pVideoStr = strstr(pSdpStr, "m=video"); if (pVideoStr != NULL) { char *pSdpStr2 = NULL; char *pSdpStr1 = strstr(pVideoStr, "a=control:"); if(pSdpStr1 != NULL) { pSdpStr1 += 10; pSdpStr2 = strstr(pSdpStr1,"\r\n"); if(pSdpStr2 == NULL) pSdpStr2 = strstr(pSdpStr1,"\n"); if(pSdpStr2 != NULL) { char pVTmp[128 + 1] = {0}; memcpy(pVTmp,pSdpStr1,pSdpStr2-pSdpStr1); pVTmp[pSdpStr2-pSdpStr1] = 0; // if(strstr(pVTmp, "rtsp://") != NULL) { CnxData.StrVStream = pVTmp; printf("Get Rtsp Step StrVStream URL<%s>!\n", pVTmp); } } else { printf("%s: Parse video control StrVStream Failure!\n%s", __FUNCTION__, pSdpStr); } } else { printf("%s: Parse sdp video control Failure!\n%s", __FUNCTION__, pSdpStr); } char *pSdpStr3 = NULL; char *pSdpStr4 = NULL; char *pAudioStr = strstr(pSdpStr2, "m=audio"); if(pAudioStr != NULL) { pSdpStr3 = strstr(pAudioStr, "a=control:"); if(pSdpStr3 != NULL) { pSdpStr3 += 10; pSdpStr4 = strstr(pSdpStr3,"\r\n"); if(pSdpStr4 == NULL) pSdpStr4 = strstr(pSdpStr3,"\n"); if(pSdpStr4 != NULL) { char pATmp[128 + 1] = {0}; memcpy(pATmp,pSdpStr3,pSdpStr4-pSdpStr3); pATmp[pSdpStr4-pSdpStr3] = 0; // if(strstr(pATmp, "rtsp://") != NULL) { CnxData.StrAStream = pATmp; printf("Get Rtsp Step StrAStream URL<%s>!\n", pATmp); } } else { //printf("%s: Parse audio control StrVStream Failure!\n%s", __FUNCTION__, pSdpStr); } } else { printf("%s: Parse sdp audio control Failure!\n%s", __FUNCTION__, pSdpStr); } } else { printf("%s: Parse sdp audio Failure!\n%s", __FUNCTION__, pSdpStr); } } else { printf("%s: Parse sdp video Failure!\n%s", __FUNCTION__, pSdpStr); } return; } /******************************************************************************* * Function: * ´¦ÀíANNOUNCEÏûÏ¢µÄ»ØÓ¦¡£ *******************************************************************************/ void CRtspClientSession::OnAnnounceResponse(CRtspResponseMsg* pMsg) { } /******************************************************************************* * Function: * ´¦ÀíGetParamÏûÏ¢µÄ»ØÓ¦¡£ *******************************************************************************/ void CRtspClientSession::OnGetParamResponse(CRtspResponseMsg* pMsg) { } /******************************************************************************* * Function: * ´¦ÀíSetParamÏûÏ¢µÄ»ØÓ¦¡£ *******************************************************************************/ void CRtspClientSession::OnSetParamResponse(CRtspResponseMsg* pMsg) { } /******************************************************************************* * Function: * ´¦ÀíSETUPÏûÏ¢µÄ»ØÓ¦¡£ *******************************************************************************/ void CRtspClientSession::OnSetupResponse(CRtspResponseMsg* pMsg) { //Check input parameters exception if (NULL == pMsg) { DBGPrint(M_RtspClientLib, ERROR_LEVEL, "%s: pMsg is null pointer!", __FUNCTION__); return; } //»ñÈ¡»á»°ID CnxData.SessionID = pMsg->GetHdr("Session"); if ( CnxData.SessionID.IsEmpty() ) { DBGPrint(M_RtspClientLib, ERROR_LEVEL, "%s: no Session header for url<%s>!", __FUNCTION__, (char*)(CPCHAR)CnxData.StrUrl); } //»ñȡýÌå¶Ë¿Ú CString StrTransport = pMsg->GetHdr("Transport"); #if 0 char needle1[] = "server_port="; char* pPortStr1 = strstr( (char*)(CPCHAR)StrTransport, needle1); if (pPortStr1 != NULL) CnxData.ServerPort = atoi(pPortStr1 + strlen(needle1) ); else printf("%s: Not found server port for url<%s>!", __FUNCTION__, (char*)(CPCHAR)CnxData.StrUrl); char needle2[] = "client_port="; char* pPortStr2 = strstr( (char*)(CPCHAR)StrTransport, needle2); if (pPortStr2 != NULL) CnxData.ClientPort = atoi(pPortStr2 + strlen(needle2) ); else printf("%s: Not found client port for url<%s>!", __FUNCTION__, (char*)(CPCHAR)CnxData.StrUrl); #endif unsigned char rtpChannelId; unsigned char rtcpChannelId; char* foundServerAddressStr = NULL; bool foundServerPortNum = false; unsigned short clientPortNum = 0; unsigned short serverPortNum = 0; bool foundClientPortNum = false; bool foundChannelIds = false; unsigned rtpCid, rtcpCid; bool isMulticast = true; // by default char* foundDestinationStr = NULL; unsigned short multicastPortNumRTP, multicastPortNumRTCP; bool foundMulticastPortNum = false; char const* fields = (CPCHAR)StrTransport; char* field = strMyDupSize(fields); while (sscanf(fields, "%[^;]", field) == 1) { if (sscanf(field, "server_port=%hu", &serverPortNum) == 1) { foundServerPortNum = true; } else if (sscanf(field, "client_port=%hu", &clientPortNum) == 1) { foundClientPortNum = true; } else if (strncasecmp(field, "source=", 7) == 0) { delete[] foundServerAddressStr; foundServerAddressStr = strMyDup(field+7); } else if (sscanf(field, "interleaved=%u-%u", &rtpCid, &rtcpCid) == 2) { rtpChannelId = (unsigned char)rtpCid; rtcpChannelId = (unsigned char)rtcpCid; foundChannelIds = true; } else if (strcmp(field, "unicast") == 0) { isMulticast = false; } else if (strncasecmp(field, "destination=", 12) == 0) { delete[] foundDestinationStr; foundDestinationStr = strMyDup(field+12); } else if (sscanf(field, "port=%hu-%hu", &multicastPortNumRTP, &multicastPortNumRTCP) == 2 || sscanf(field, "port=%hu", &multicastPortNumRTP) == 1) { foundMulticastPortNum = true; } fields += strlen(field); while (fields[0] == ';') ++fields; // skip over all leading ';' chars if (fields[0] == '\0') break; } delete[] field; CnxData.ServerPort = serverPortNum; CnxData.ClientPort = clientPortNum; if (foundServerAddressStr != NULL) CnxData.strServerIp = foundServerAddressStr; else CnxData.strServerIp = pTcpTransport->sIpAddr; delete[] foundDestinationStr; delete[] foundServerAddressStr; char pMyIpStr[24] = {0}; GetLocalIP(pMyIpStr, 24); CnxData.strClientIp = pMyIpStr; printf("%s:%d ServerPort:%u, ClientPort:%u, strServerIp:%s, strClientIp:%s\n", __FUNCTION__, __LINE__, CnxData.ServerPort, CnxData.ClientPort, CnxData.strServerIp.c_str(), CnxData.strClientIp.c_str()); } /******************************************************************************* * Function: * ´¦ÀíPLAYÏûÏ¢µÄ»ØÓ¦¡£ *******************************************************************************/ void CRtspClientSession::OnPlayResponse(CRtspResponseMsg* pMsg) { //Check input parameters exception if (NULL == pMsg) { printf("%s: pMsg is null pointer!", __FUNCTION__); return; } } /******************************************************************************* * Function: * ´¦ÀíPAUSEÏûÏ¢µÄ»ØÓ¦¡£ *******************************************************************************/ void CRtspClientSession::OnPauseResponse(CRtspResponseMsg* pMsg) { } /******************************************************************************* * Function: * ´¦ÀíRECORDÏûÏ¢µÄ»ØÓ¦¡£ *******************************************************************************/ void CRtspClientSession::OnRecordResponse(CRtspResponseMsg* pMsg) { } /******************************************************************************* * Function: * ´¦ÀíREDIRECTÏûÏ¢µÄ»ØÓ¦¡£ *******************************************************************************/ void CRtspClientSession::OnRedirectResponse(CRtspResponseMsg* pMsg) { } /******************************************************************************* * Function: * ´¦ÀíTEARDOWNÏûÏ¢µÄ»ØÓ¦¡£ *******************************************************************************/ void CRtspClientSession::OnTeardownResponse(CRtspResponseMsg* pMsg) { //Check input parameters exception if (NULL == pMsg) { DBGPrint(M_RtspClientLib, ERROR_LEVEL, "%s: pMsg is null pointer!", __FUNCTION__); return; } } /******************************************************************************* * Function: * ´¦ÀíEXTENSIONÏûÏ¢µÄ»ØÓ¦¡£ *******************************************************************************/ void CRtspClientSession::OnExtensionResponse(CRtspResponseMsg* pMsg) { } /******************************************************************************* * Function: * RTSP¿Í»§¶Ë·¢ËÍÏûÏ¢½»»¥Ö÷Òª²Ù×÷¹ý³Ì£¬Íê³ÉÏûÏ¢±àÂë¡¢·¢ËÍ¡¢½ÓÊÕ¡¢½âÎöºÍÁ÷³ÌÇý¶¯¡£ *******************************************************************************/ int CRtspClientSession::DoWork(CRtspRequestMsg& ReqMsg) { char* pNewBuf = NULL; int BufLen = 0; int iRet = pRtspProt->Encoder(&ReqMsg, pNewBuf, BufLen); if (0 == iRet) { // printf("-------------------------Send-----------------------------\n"); // printf("%s\n",pNewBuf); iRet = SendData(pNewBuf, BufLen); //Note: pNewBuf is dynamic memory alloc pointer! so free it. delete [] pNewBuf; if (iRet > 0) { BufLen = RTSP_MESSAGE_MAX_LEN; memset(DataBuf, 0, sizeof(DataBuf)); int DataLen = ReadData(DataBuf, BufLen, 5); //wait 2 seconds //waite 1 senconds if (DataLen > 0) { CRtspProtocol::CRtspRequestTag* pRequestTag = new CRtspProtocol::CRtspRequestTag(atoi(ReqMsg.GetHdr("CSeq") ), ReqMsg.GetVerb() ); if (pRequestTag != NULL) { if (pRtspProt->RequestTagListQueue.insert(pRequestTag) != -1) { CRtspMsg* pRtspMsg = NULL; int code = 0; int iRet2 = pRtspProt->DecoderAndDrvie(DataBuf, DataLen, pRtspMsg, code); if (0 == iRet2) { if (pRtspMsg != NULL) { CnxData.StatusCode = ( (CRtspResponseMsg*)pRtspMsg)->GetStatusCode(); SAFE_DELETE(pRtspMsg); //ÊÍ·ÅÄÚ´æ } if (CnxData.StatusCode != 200 && CnxData.StatusCode != 401) { printf("%s:%d Recv a error message from Url<%s>!\n%s", __FUNCTION__, __LINE__, (char*)(CPCHAR)CnxData.StrUrl, DataBuf); return -1; } return 0; } else { if (pRtspMsg != NULL) { CnxData.StatusCode = ( (CRtspResponseMsg*)pRtspMsg)->GetStatusCode(); SAFE_DELETE(pRtspMsg); //ÊÍ·ÅÄÚ´æ } printf("%s:%d Recv a error message from Url<%s>!\n%s", __FUNCTION__, __LINE__, (char*)(CPCHAR)CnxData.StrUrl, DataBuf); /* ±±¾©¹«½»BTÏîÄ¿ÎݲÉ豸ÔÚGET_PARAMETERʱ£¬»ØÓ¦ÏÂÁаü£¬°ü½áβûÓÐ/r/n£¬µ¼Ö½âÎö³ö´í£¬ÏµÍ³±ÀÀ£¡£ --yinxiaogui 2014/3/7 13:59:24 * "RTSP/1.0 200 OK\r\nCSeq: 6\r\nDate: Fri, Mar 07 2014 12:04:00 GMT\r\nContent-Base: rtsp://" */ if ( (200 == CnxData.StatusCode) && (412 == code) ) return 0; return -1; } } else { printf("Rtsp request tag insert: fatal error!\n"); delete pRequestTag; return -1; } } else { printf("%s: new CRtspRequestTag fail!\n", __FUNCTION__); return -1; } } else { printf("%s: Read data error, len: %d, Url<%s>!\n", __FUNCTION__, DataLen, (char*)(CPCHAR)CnxData.StrUrl); return -1; } } else { printf("%s: Send data error: Url<%s>!\n", __FUNCTION__, (char*)(CPCHAR)CnxData.StrUrl); return -1; } } else { if (RTSP_TYPE_REQUEST == ReqMsg.GetType() ) { printf("%s: Translate rtsp request<%s> message into str failed!\n", __FUNCTION__, ReqMsg.GetVerbStr() ); } else { printf("%s: no request message!\n", __FUNCTION__); } return -1; } return 0; } /******************************************************************************* * Function: * ͨ¹ý´«Êä²ã·¢ËÍÐÅÁ·¢ËÍÊý¾ÝΪ×èÈûģʽ¡£ *******************************************************************************/ int CRtspClientSession::SendData(const char* pBuf, int Len, const int WaitForTimeout) { struct pollfd FdSet[1] = { {0, 0} }; FdSet[0].fd = pTcpTransport->SockFd; //FdSet[0].events = POLLOUT | POLLRDHUP; FdSet[0].events = POLLOUT; //ÂÖÑ¯ÍøÂçFD£¬¿ÉÒÔд»òÕßÒì³£Á¢¼´·µ»Ø£¬²»ÄÜдµÈ´ý³¬Ê±¡£ if ( (poll(FdSet, 1, WaitForTimeout * 1000) < 0) && (errno != EINTR) ) { printf("%s poll error: SockFd<%d>, Url<%s>!", __FUNCTION__, pTcpTransport->SockFd, (char*)(CPCHAR)CnxData.StrUrl); return -1; } return pTcpTransport->Send( (UINT8*)pBuf, Len); } /******************************************************************************* * Function: * ͨ¹ý´«Êä²ã½ÓÊÕÐÅÁî¡£ *******************************************************************************/ int CRtspClientSession::ReadData(const char* pBuf, int BufLen, const int WaitForTimeout) { struct pollfd FdSet[1] = { {0, 0} }; FdSet[0].fd = pTcpTransport->SockFd; FdSet[0].events = POLLIN | POLLPRI; //ÂÖÑ¯ÍøÂçFD£¬ÓÐÊý¾Ý»òÕßÒì³£Á¢¼´·µ»Ø£¬ÎÞÊý¾ÝµÈ´ý³¬Ê±¡£ int ret = poll(FdSet, 1, WaitForTimeout * 1000); if ( (ret < 0) && (errno != EINTR) ) { printf("%s poll error: SockFd<%d>, Url<%s>!\n", __FUNCTION__, pTcpTransport->SockFd, (char*)(CPCHAR)CnxData.StrUrl); return -1; } printf("poll return %d\n", ret); //ÅжÏÊý¾Ý¿É¿¿ÐÔ£¿ if ( ( (FdSet[0].revents & POLLIN) == POLLIN) || ( (FdSet[0].revents & POLLPRI) == POLLPRI) ) { //return pTcpTransport->Read( (UINT8*)pBuf, BufLen); return ReadRtspData( (UINT8*)pBuf, BufLen); } else { printf("revents error: 0x%x\n",FdSet[0].revents); } return 0; } int CRtspClientSession::ReadRtspData(UINT8 *pBuf, int BufLen) { printf("ReadRtspData!\n"); int DataLen = pTcpTransport->Read( (UINT8*)pBuf, BufLen, MSG_PEEK); if (DataLen <= 0) { return DataLen; } printf("Begin to parse RTSP!\n"); //1. Begin to parse RTSP, HTTP format data char* p2CRLF = strstr( (char*)pBuf, "\r\n\r\n"); if (p2CRLF != NULL) { int TheMsgLen = (long)p2CRLF - (long)pBuf + 4; pBuf[TheMsgLen] = 0; char* pContentLength = strstr( (char*)pBuf, "Content-Length"); if (pContentLength != NULL) { pContentLength += sizeof("Content-length"); while ( (*pContentLength == ':') || (*pContentLength == ' ') ) pContentLength++; TheMsgLen += atoi(pContentLength); } DataLen = pTcpTransport->Read( (UINT8*)pBuf, BufLen, 0); if (DataLen == TheMsgLen) { return DataLen; } else { int dataLen1 = 0; if (DataLen > 0) { dataLen1 = pTcpTransport->Read( (UINT8*)&pBuf[DataLen], BufLen, 0); if (dataLen1 + DataLen >= TheMsgLen) { return dataLen1 + DataLen; } } printf("TCP Recv <%d, %d> bytes but no match <%d> bytes!\n%s\n", DataLen, dataLen1, TheMsgLen, (char *)pBuf); } } else { //panasonic dev : teardown ret is: RTSP/1.0 200 OK\r\nCSeq: 4\r\n ȱÉÙ\r\n char* p2CRLF = strstr( (char*)pBuf, "RTSP/1.0 200 OK\r\nCSeq:"); if (p2CRLF != NULL) { int TheMsgLen = DataLen; DataLen = pTcpTransport->Read( (UINT8*)pBuf, BufLen, 0); if (DataLen == TheMsgLen) { strcat((char*)pBuf, "\r\n"); return DataLen + 2; } else { int dataLen1 = 0; if (DataLen > 0) { dataLen1 = pTcpTransport->Read( (UINT8*)&pBuf[DataLen], BufLen, 0); if (dataLen1 + DataLen >= TheMsgLen) { return dataLen1 + DataLen; } } printf("TCP Recv <%d> bytes but no match <%d> bytes!!!\n%s\n", DataLen, TheMsgLen, (char *)pBuf); } } printf("%s: parse rtsp data error, datalen(%d)\n%s!\n", __FUNCTION__, DataLen, pBuf); usleep(1000); } pTcpTransport->Read( (UINT8*)pBuf, BufLen, 0); pBuf[0] = 0; return 0; }