/******************************************************************************
|
* 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; i+=A_SESSION_OCCUPY_MEDIA_PORT)
|
{
|
PId = RtspCurrentPort;
|
RtspCurrentPort += A_SESSION_OCCUPY_MEDIA_PORT;
|
if (RtspCurrentPort >= 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;
|
}
|
|