/***************************************************************************************
*
* IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
*
* By downloading, copying, installing or using the software you agree to this license.
* If you do not agree to this license, do not download, install,
* copy or use the software.
*
* Copyright (C) 2010-2014, Happytimesoft Corporation, all rights reserved.
*
* Redistribution and use in binary forms, with or without modification, are permitted.
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
* language governing permissions and limitations under the License.
*
****************************************************************************************/
#include <string.h>
#include <stdio.h>
#include "sys_inc.h"
#include "rtp.h"
#include "rtsp.h"
#include <process.h>
#include "../rtspdll.h"
#include "../CLock.h"
#include "word_analyse.h"
#include "rfc_md5.h"
#include <map>
#define HASHLEN 16
typedef unsigned char HASH[HASHLEN];
#define HASHHEXLEN 32
typedef char HASHHEX[HASHHEXLEN + 1];
void CvtHex(HASH Bin, HASHHEX Hex)
{
unsigned short i;
unsigned char j;
for (i = 0; i < HASHLEN; i++) {
j = (Bin[i] >> 4) & 0xf;
if (j <= 9)
Hex[i * 2] = (j + '0');
else
Hex[i * 2] = (j + 'a' - 10);
j = Bin[i] & 0xf;
if (j <= 9)
Hex[i * 2 + 1] = (j + '0');
else
Hex[i * 2 + 1] = (j + 'a' - 10);
};
Hex[HASHHEXLEN] = '\0';
};
void * CRtsp::rtsp_rx_thread(void * argv)
{
CRtsp * pRtsp = (CRtsp *)argv;
pRtsp->rx_thread();
return NULL;
}
void * CRtsp::rtsp_udp_thread(void *argv)
{
CRtsp * pRtsp = (CRtsp *)argv;
pRtsp->udp_thread();
return NULL;
}
CRtsp::CRtsp(void)
{
m_rtspRxTid = 0;
m_pNotify = 0;
m_pUserdata = 0;
m_r264_fu_s = 0;
m_r264_fu_nalu = 0;
m_r264_fu_header = 0;
m_r264_fu_offset = 0;
//m_pcRua = new CRua();
//memset(m_pcRua, 0, sizeof(CRua));
memset(&m_rua, 0, sizeof(RUA));
}
CRtsp::~CRtsp(void)
{
rtsp_close();
//delete m_pcRua;
}
bool CRtsp::rtsp_client_start()
{
if (rua_init_connect() == false)
{
log_print("rua_init_connect fail!!!\r\n");
return false;
}
m_rua.cseq = 1;
CRtspParse * pSendMsg = rua_build_describe();
if (pSendMsg)
{
send_rtsp_msg(pSendMsg);
delete pSendMsg;
}
m_rua.state = RCS_DESCRIBE;
return true;
}
bool CRtsp::rua_init_connect()
{
//tcp
SOCKET fd = socket(AF_INET,SOCK_STREAM,0);
if (fd == -1)
{
log_print("rua_init_connect::socket fail!!!\r\n");
return false;
}
log_print("rua_init_connect::fd = %d\r\n",fd);
if (m_rua.lport != 0)
{
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(m_rua.lport);
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
{
log_print("rua_init_connect::bind lport[%u] fail.\n", m_rua.lport);
closesocket(fd);
return false;
}
}
struct sockaddr_in raddr;
raddr.sin_family = AF_INET;
raddr.sin_addr.s_addr = inet_addr(m_rua.ripstr);
raddr.sin_port = htons(m_rua.rport);
struct timeval timeo = {5, 0};
setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeo, sizeof(timeo));
if (connect(fd, (struct sockaddr *)&raddr, sizeof(struct sockaddr_in)) == -1)
{
log_print("rua_init_connect::connect %s:%u fail!!!\r\n", m_rua.ripstr, m_rua.rport);
closesocket(fd);
return false;
}
int len = 1024 * 1024;
if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char*)&len, sizeof(int)))
{
log_print("setsockopt SO_RCVBUF error!\n");
return false;
}
m_rua.fd = fd;
//udp
if (m_transType == 0)//udp
{
SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock == INVALID_SOCKET)
{
closesocket(fd);
return false;
}
struct sockaddr_in addrClient;
addrClient.sin_family = AF_INET;
addrClient.sin_addr.s_addr = htonl(INADDR_ANY);
addrClient.sin_port = 0;
if (bind(sock, (SOCKADDR*)&addrClient, sizeof(sockaddr_in)) == SOCKET_ERROR)
{
closesocket(sock);
closesocket(fd);
return false;
}
int addrLen = sizeof(sockaddr_in);
if (getsockname(sock, (SOCKADDR*)&addrClient, &addrLen)==SOCKET_ERROR)
{
closesocket(sock);
closesocket(fd);
return false;
}
m_rua.udpPort = ntohs(addrClient.sin_port);
m_rua.udpSock = sock;
m_rua.pUdpBuf = new char[4 * 1024 * 1024];
m_rua.udpBufLen = 4 * 1024 * 1024;
m_udpRecvTid=sys_os_create_thread((void *)rtsp_udp_thread, this);
if (m_udpRecvTid == 0)
{
closesocket(sock);
closesocket(fd);
return false;
}
}
return true;
}
void CRtsp::rtsp_client_stop()
{
if (m_rua.fd > 0)
{
CRtspParse * pSendMsg = rua_build_teardown();
if (pSendMsg)
{
send_rtsp_msg( pSendMsg);
delete pSendMsg;
}
}
}
bool CRtsp::rtsp_start(char* url, char* ip, int port, const char * user, const char * pass,int transType)
{
if (m_rua.state != RCS_NULL)
{
rtsp_play();
return true;
}
//memset(&m_rua, 0, sizeof(RUA));
//memset(m_url, 0, sizeof(m_url));
//memset(m_ip, 0, sizeof(m_ip));
if (user)
{
strcpy(m_rua.user_auth_info.auth_name, user);
}
if (pass)
{
strcpy(m_rua.user_auth_info.auth_pwd, pass);
}
if (url)
{
//strcpy(m_url, url);
strcpy(m_rua.uri, url);
}
if (ip)
{
//strcpy(m_ip, ip);
strcpy(m_rua.ripstr, ip);
}
//m_nport = port;
m_rua.rport = port;
m_transType = transType;
m_rtspRxTid = sys_os_create_thread((void *)rtsp_rx_thread, this);
if (m_rtspRxTid == 0)
{
log_print((char *)"start_video::pthread_create rtsp_rx_thread failed!!!\r\n");
return false;
}
return true;
}
bool CRtsp::rtsp_play()
{
m_rua.cseq++;
CRtspParse * pSendMsg = rua_build_play();
if (pSendMsg)
{
send_rtsp_msg(pSendMsg);
delete pSendMsg;
}
return true;
}
bool CRtsp::rtsp_stop()
{
m_rua.cseq++;
CRtspParse * pSendMsg = rua_build_teardown();
if (pSendMsg)
{
send_rtsp_msg(pSendMsg);
delete pSendMsg;
}
m_rua.state = RCS_NULL;
return true;
}
bool CRtsp::rtsp_pause()
{
m_rua.cseq++;
CRtspParse * pSendMsg = rua_build_pause();
if (pSendMsg)
{
send_rtsp_msg(pSendMsg);
delete pSendMsg;
}
return true;
}
bool CRtsp::rtsp_close()
{
if (m_rua.fd)
{
closesocket(m_rua.fd);
m_rua.fd = 0;
}
while (m_rtspRxTid != 0)
{
usleep(10 * 1000); // 10ms wait
}
return true;
}
void CRtsp::DescribeMsg200Proc(CRtspParse * pRecvMsg)
{
pRecvMsg->get_rtsp_session_info(m_rua.sid, sizeof(m_rua.sid) - 1);
char cseq_buf[32];
char cbase[256];
pRecvMsg->get_rtsp_msg_cseq(cseq_buf, sizeof(cseq_buf)-1);
//Content-Base
if (pRecvMsg->get_rtsp_cbase_info(cbase, sizeof(cbase)-1))
{
strncpy(m_rua.uri, cbase, sizeof(m_rua.uri) - 1);
}
pRecvMsg->find_rtsp_sdp_control(m_rua.v_ctl, (char *)"video", sizeof(m_rua.v_ctl) - 1);
pRecvMsg->find_rtsp_sdp_control(m_rua.a_ctl, (char *)"audio", sizeof(m_rua.a_ctl) - 1);
get_rtsp_media_info(pRecvMsg);
//Send SETUP
if (m_rua.v_ctl[0] != '\0')
{
m_rua.v_interleaved = 0;
m_rua.cseq++;
CRtspParse *pSendMsg = rua_build_setup(0);
if (pSendMsg)
{
send_rtsp_msg(pSendMsg);
delete pSendMsg;
}
}
m_rua.state = RCS_INIT_V;
}
void CRtsp::DescribeMsg401Proc(CRtspParse * pRecvMsg)
{
m_rua.need_auth = TRUE;
if (pRecvMsg->rtsp_get_digest_info(&m_rua.user_auth_info))
{
m_rua.auth_mode = 1;
sprintf(m_rua.user_auth_info.auth_uri, "%s", m_rua.uri);
}
else
{
m_rua.auth_mode = 0;
}
CRtspParse * pSendMsg = rua_build_describe();
if (pSendMsg)
{
send_rtsp_msg(pSendMsg);
de