Initial setup for CLion

This commit is contained in:
2026-03-28 16:54:11 +11:00
parent 239cc02591
commit 7b4134133c
1136 changed files with 811916 additions and 0 deletions

View File

@@ -0,0 +1,337 @@
/***************************************************************************************
*
* 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) 2014-2024, 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 "sys_inc.h"
#include "rtsp_backchannel.h"
#include "rtsp_rcua.h"
#include "rtp.h"
#include "rtsp_util.h"
#include "base64.h"
#include "http_cln.h"
#include "media_format.h"
#ifdef OVER_WEBSOCKET
#include "rtsp_ws.h"
#endif
#ifdef BACKCHANNEL
/***************************************************************************************/
/**
* Send rtp data by TCP socket
*
* @param p_rua rtsp user agent
* @param p_data rtp data
* @param len rtp data len
* @return -1 on error, or the data length has been sent
*/
int rtp_tcp_tx(RCUA * p_rua, uint8 * p_data, int len)
{
int offset = 0;
SOCKET fd;
int buflen;
char * p_buff;
#ifdef OVER_HTTP
if (p_rua->over_http)
{
fd = p_rua->rtsp_send.cfd;
}
else
#endif
#ifdef OVER_WEBSOCKET
if (p_rua->over_ws)
{
fd = p_rua->ws_http.cfd;
}
else
#endif
fd = p_rua->fd;
if (fd <= 0)
{
return -1;
}
#ifdef OVER_HTTP
if (p_rua->over_http)
{
char * tx_buf_base64 = (char *)malloc(2 * len);
if (NULL == tx_buf_base64)
{
return -1;
}
if (0 == base64_encode(p_data, len, tx_buf_base64, 2 * len))
{
free(tx_buf_base64);
return -1;
}
p_buff = tx_buf_base64;
buflen = strlen(tx_buf_base64);
}
else
#endif
#ifdef OVER_WEBSOCKET
if (p_rua->over_ws)
{
int extra = rtsp_ws_encode_data(p_data, len, 0x82, 1);
p_buff = (char *)(p_data - extra);
buflen = len + extra;
}
else
#endif
{
p_buff = (char *)p_data;
buflen = len;
}
while (offset < buflen)
{
int tlen;
#ifdef OVER_HTTP
if (p_rua->over_http)
{
tlen = http_cln_tx(&p_rua->rtsp_send, p_buff+offset, buflen-offset);
}
else
#endif
#ifdef OVER_WEBSOCKET
if (p_rua->over_ws)
{
tlen = http_cln_tx(&p_rua->ws_http, p_buff+offset, buflen-offset);
}
else
#endif
tlen = send(fd, (const char *)p_buff+offset, buflen-offset, 0);
if (tlen > 0)
{
offset += tlen;
}
else
{
int sockerr = sys_os_get_socket_error_num();
if (sockerr == EINTR || sockerr == EAGAIN)
{
usleep(1000);
continue;
}
log_print(HT_LOG_ERR, "%s, send failed, fd[%d], tlen[%d,%d], err[%d][%s]!!!\r\n",
__FUNCTION__, fd, tlen, buflen-offset, sockerr, sys_os_get_socket_error());
break;
}
}
#ifdef OVER_HTTP
if (p_rua->over_http)
{
free(p_buff);
}
#endif
return (offset == buflen) ? len : -1;
}
int rtp_udp_tx(RCUA * p_rua, int av_t, uint8 * p_data, int len)
{
int slen;
SOCKET fd = 0;
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(p_rua->ripstr);
if (AV_TYPE_BACKCHANNEL == av_t)
{
addr.sin_port = htons(p_rua->channels[av_t].r_port);
fd = p_rua->channels[av_t].udp_fd;
if (p_rua->rtp_mcast)
{
addr.sin_addr.s_addr = inet_addr(p_rua->channels[av_t].destination);
}
}
if (fd <= 0)
{
return -1;
}
slen = sendto(fd, (char *)p_data, len, 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
if (slen != len)
{
log_print(HT_LOG_ERR, "%s, slen = %d, len = %d, ip=0x%08x\r\n", __FUNCTION__, slen, len, p_rua->ripstr);
}
return slen;
}
/**
* Build audio rtp packet and send
*
* @param p_rua rtsp user agent
* @param p_data payload data
* @param len payload data length
* @ts the packet timestamp
* @return the rtp packet length, -1 on error
*/
int rtp_audio_build(RCUA * p_rua, uint8 * p_data, int len, uint32 ts, int mbit)
{
int offset = 0;
int slen = 0;
uint8 * p_rtp_ptr = p_data - 12; // shift forward RTP head
if (p_rua->rtp_tcp)
{
p_rtp_ptr -= 4;
*(p_rtp_ptr+offset) = 0x24; // magic
offset++;
*(p_rtp_ptr+offset) = p_rua->channels[AV_BACK_CH].interleaved; // channel
offset++;
offset += rtp_write_uint16(p_rtp_ptr+offset, 12 + len); // rtp payload length
}
*(p_rtp_ptr+offset) = (RTP_VERSION << 6);
offset++;
*(p_rtp_ptr+offset) = (p_rua->bc_rtp_info.rtp_pt) | ((mbit & 0x01) << 7);
offset++;
offset += rtp_write_uint16(p_rtp_ptr+offset, p_rua->bc_rtp_info.rtp_cnt);
offset += rtp_write_uint32(p_rtp_ptr+offset, p_rua->bc_rtp_info.rtp_ts);
offset += rtp_write_uint32(p_rtp_ptr+offset, p_rua->bc_rtp_info.rtp_ssrc);
if (p_rua->rtp_tcp)
{
slen = rtp_tcp_tx(p_rua, p_rtp_ptr, offset+len);
}
else
{
slen = rtp_udp_tx(p_rua, AV_TYPE_BACKCHANNEL, p_rtp_ptr, offset+len);
}
p_rua->bc_rtp_info.rtp_cnt = (p_rua->bc_rtp_info.rtp_cnt + 1) & 0xFFFF;
return (slen == offset+len) ? slen : -1;
}
/**
* Build audio rtp packet and send (not fragment)
*
* @param p_rua rtsp user agent
* @param p_data payload data
* @param len payload data length
* @ts the packet timestamp
* @return the rtp packet length, -1 on error
*/
int rtp_audio_tx(RCUA * p_rua, uint8 * p_data, int size, uint32 ts)
{
return rtp_audio_build(p_rua, p_data, size, ts, 1);
}
int rtp_aac_audio_tx(RCUA * p_rua, uint8 * p_data, int size, uint32 ts)
{
int ret = 0;
int len, max_packet_size, au_size;
uint8 *p;
max_packet_size = RTP_MAX_LEN;
if (p_data[0] == 0xFF && (p_data[1] & 0xF0) == 0xF0)
{
// skip ADTS header
p_data += 7;
size -= 7;
}
p = p_data - 4;
au_size = size;
while (size > 0)
{
len = MIN(size, max_packet_size);
rtp_write_uint16(p, 2 * 8);
rtp_write_uint16(&p[2], au_size * 8);
ret = rtp_audio_build(p_rua, p, len + 4, ts, len == size);
if (ret < 0)
{
break;
}
size -= len;
p += len;
}
return ret;
}
void rtsp_bc_cb(uint8 *data, int size, int nbsamples, void *pUserdata)
{
RCUA * p_rua = (RCUA *)pUserdata;
if (p_rua->send_bc_data)
{
uint8 * p_buf = NULL;
p_buf = (uint8 *)malloc(size + 40);
if (p_buf == NULL)
{
log_print(HT_LOG_ERR, "%s, malloc failed!!!\r\n", __FUNCTION__);
return;
}
uint8 * p_tbuf = p_buf + 40; // shift forword header
memcpy(p_tbuf, data, size);
if (AUDIO_CODEC_AAC == p_rua->bc_audio_codec)
{
rtp_aac_audio_tx(p_rua, p_tbuf, size, rtsp_get_timestamp(nbsamples));
}
else
{
rtp_audio_tx(p_rua, p_tbuf, size, rtsp_get_timestamp(nbsamples));
}
free(p_buf);
}
}
#else
void rtsp_bc_cb(uint8 *data, int size, int nbsamples, void *pUserdata)
{
}
#endif // BACKCHANNEL

View File

@@ -0,0 +1,37 @@
/***************************************************************************************
*
* 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) 2014-2024, 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.
*
****************************************************************************************/
#ifndef RTSP_BACKCHANNEL_H
#define RTSP_BACKCHANNEL_H
#ifdef __cplusplus
extern "C" {
#endif
void rtsp_bc_cb(uint8 * data, int size, int nbsamples, void * pUserdata);
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

443
MediaClient/rtsp/rtsp_cln.h Normal file
View File

@@ -0,0 +1,443 @@
/***************************************************************************************
*
* 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) 2014-2024, 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.
*
****************************************************************************************/
#ifndef RTSP_CLN_H
#define RTSP_CLN_H
#include "sys_buf.h"
#include "rtsp_rcua.h"
#include "media_format.h"
#include "h264_rtp_rx.h"
#include "mjpeg_rtp_rx.h"
#include "h265_rtp_rx.h"
#include "mpeg4_rtp_rx.h"
#include "aac_rtp_rx.h"
#include "pcm_rtp_rx.h"
typedef int (*notify_cb)(int, void *);
typedef int (*video_cb)(uint8 *, int, uint32, uint16, void *);
typedef int (*audio_cb)(uint8 *, int, uint32, uint16, void *);
typedef int (*rtcp_cb)(uint8 *, int, int, void *);
typedef int (*metadata_cb)(uint8 *, int, uint32, uint16, void *);
#define RTSP_EVE_STOPPED 0 // stopped
#define RTSP_EVE_CONNECTING 1 // connecting
#define RTSP_EVE_CONNFAIL 2 // connect failed
#define RTSP_EVE_CONNSUCC 3 // connect success
#define RTSP_EVE_NOSIGNAL 4 // no signal
#define RTSP_EVE_RESUME 5 // resume
#define RTSP_EVE_AUTHFAILED 6 // authentication failed
#define RTSP_EVE_NODATA 7 // No data received within the timeout period
#define RTSP_RX_FAIL -1 // rtsp data receive failed
#define RTSP_RX_TIMEOUT 1 // rtsp data receive timeout
#define RTSP_RX_SUCC 2 // rtsp data receive success
#define RTSP_PARSE_FAIL -1 // rtsp message parse failed
#define RTSP_PARSE_MOREDATA 0 // need more data to parse rtsp message
#define RTSP_PARSE_SUCC 1 // rtsp message parse success
class CRtspClient
{
public:
CRtspClient(void);
~CRtspClient(void);
public:
BOOL rtsp_start(const char * suffix, const char * ip, int port, const char * user, const char * pass);
BOOL rtsp_start(const char * url, const char * user, const char * pass);
BOOL rtsp_play(int npt_start = 0);
BOOL rtsp_stop();
BOOL rtsp_pause();
BOOL rtsp_close();
RCUA * get_rua() {return &m_rua;}
char * get_url() {return m_url;}
char * get_ip() {return m_ip;}
int get_port() {return m_nport;}
char * get_user() {return m_rua.auth_info.auth_name;}
char * get_pass() {return m_rua.auth_info.auth_pwd;}
void set_notify_cb(notify_cb notify, void * userdata);
void set_video_cb(video_cb cb);
void set_audio_cb(audio_cb cb);
void set_metadata_cb(metadata_cb cb);
void set_rtcp_cb(rtcp_cb cb);
/**
* @desc : set channel flags
* @params :
* channel:
* AV_VIDEO_CH : video channel
* AV_AUDIO_CH : audio channel
* AV_METADATA_CH : metadata channel
* AV_BACK_CH : audio back channel
*
* flag : 1 - If the SDP description has the channel information, then SETUP this channel,
* 0 - DO NOT SETUP THIS CHANNEL
*
* note : All channels are setup by default
*/
void set_channel(int channel, int flag);
/**
* @desc : Set rtp multicast
* @params :
* flag : 1 - enable rtp multcast, 0 - disable rtp multcast
*/
void set_rtp_multicast(int flag);
/**
* @desc : Set rtp over udp
* @params :
* flag : 1 - enable rtp over udp, 0 - disable rtp over udp
*/
void set_rtp_over_udp(int flag);
/**
* @desc : Set rtsp over http
* @params :
* flag : 1 - enable rtsp over http, 0 - disable rtsp over http
* port : if flag = 1, specify the http port
*/
void set_rtsp_over_http(int flag, int port);
/**
* @desc : Set rtsp over websocket
* @params :
* flag : 1 - enable rtsp over websocket, 0 - disable rtsp over websocket
* ws_uri : if flag = 1, specify the websocket port
*/
void set_rtsp_over_ws(int flag, int port);
/**
* @desc : Set the data rx timeout, if the data is not received within the specified time,
* send RTSP_EVE_NODATA notification
* @params :
* timeout : Timeout value, unit is second
*/
void set_rx_timeout(int timeout);
/**
* @desc : Set the connect timeout
* @params :
* timeout : Timeout value, unit is second
*/
void set_conn_timeout(int timeout);
/**
* @desc : Get H264, SPS, PPS parameters, and return through the video callback function
*/
void get_h264_params();
/**
* @desc : Get H264, SPS, PPS parameters
* @params
* p_sps : Receive H264 SPS data, the buffer size is not less than 256
* sps_len : Receive H264 SPS buffer length
* p_pps : Receive H264 PPS data, the buffer size is not less than 256
* pps_len : Receive H264 PPS buffer length
*/
BOOL get_h264_params(uint8 * p_sps, int * sps_len, uint8 * p_pps, int * pps_len);
/**
* @desc : Get H265, VPS, SPS, PPS parameters, and return through the video callback function
*/
void get_h265_params();
/**
* @desc : Get H265, VPS, SPS, PPS parameters
* @params
* p_sps : Receive H264 SPS data, the buffer size is not less than 256
* sps_len : Receive H264 SPS buffer length
* p_pps : Receive H264 PPS data, the buffer size is not less than 256
* pps_len : Receive H264 PPS buffer length
* p_vps : Receive H264 VPS data, the buffer size is not less than 256
* vps_len : Receive H264 VPS buffer length
*/
BOOL get_h265_params(uint8 * p_sps, int * sps_len, uint8 * p_pps, int * pps_len, uint8 * p_vps, int * vps_len);
/**
* @desc : If the describe request response returned by the server has an H264 SDP description, get the H264 SDP description
* @params
* p_sdp : Receive H264 SDP description
* max_len : Maximum length of buffer p_sdp
*/
BOOL get_h264_sdp_desc(char * p_sdp, int max_len);
/**
* @desc : If the describe request response returned by the server has an H265 SDP description, get the H265 SDP description
* @params
* p_sdp : Receive H265 SDP description
* max_len : Maximum length of buffer p_sdp
*/
BOOL get_h265_sdp_desc(char * p_sdp, int max_len);
/**
* @desc : If the describe request response returned by the server has an H265 SDP description, get the MP4 SDP description
* @params
* p_sdp : Receive MP4 SDP description
* max_len : Maximum length of buffer p_sdp
*/
BOOL get_mp4_sdp_desc(char * p_sdp, int max_len);
/**
* @desc : If the describe request response returned by the server has an H265 SDP description, get the AAC SDP description
* @params
* p_sdp : Receive AAC SDP description
* max_len : Maximum length of buffer p_sdp
*/
BOOL get_aac_sdp_desc(char * p_sdp, int max_len);
/**
* @desc : Get video codec
* @retrun : reference the media_format.h, VIDEO_CODEC_H264, ...
*/
int audio_codec() {return m_rua.audio_codec;}
/**
* @desc : Get audio codec
* @retrun : reference the media_format.h, AUDIO_CODEC_AAC, ...
*/
int video_codec() {return m_rua.video_codec;}
/**
* @desc : Get audio sample rate
*/
int get_audio_samplerate() {return m_rua.sample_rate;}
/**
* @desc : Get audio channel numbers
*/
int get_audio_channels() {return m_rua.audio_channels;}
/**
* @desc : Get audio bits per sample, for G726 decoder
*/
int get_audio_bitpersample() {return m_rua.bit_per_sample;}
/**
* @desc : Get audio config data, for AAC
*/
uint8 * get_audio_config() {return m_rua.audio_spec;}
/**
* @desc : Get audio config data length, for AAC
*/
int get_audio_config_len() {return m_rua.audio_spec_len;}
/**
* @desc : get the audio backchannel flag
*/
int get_bc_flag();
/**
* @desc : set the audio backchannel flag
* @params
* flag : 1 - enable audio backchannel; 0 - disable audio backchannel
*/
void set_bc_flag(int flag);
/**
* @desc : get the audio backchannel data sending flag
*/
int get_bc_data_flag();
/**
* @desc : set the audio backchannel data sending flag
* @params
* flag : 1 - enable audio backchannel data sending; 0 - disable audio backchannel data sending
*/
void set_bc_data_flag(int flag);
/**
* @desc : set the audio backchannel audio capture device index
* @params
* index : audio capture device index
*/
void set_audio_device(int index);
/**
* @desc : get the replay flag
*/
int get_replay_flag();
/**
* @desc : set the replay flag
* @params
* flag : 1 - enable replay; 0 - disable replay
*/
void set_replay_flag(int flag);
/**
* @desc : set the scale info
* @params
* scale : when not set the rata control flag, the scale is valid.
* It shall be either 1.0 or -1.0, to indicate forward or reverse playback respectively.
* If it is not present, forward playback is assumed
*/
void set_scale(double scale);
/**
* @desc : set the rate control flag
* @params
* flag :
* 1-the stream is delivered in real time using standard RTP timing mechanisms
* 0-the stream is delivered as fast as possible, using only the flow control provided by the transport to limit the delivery rate
*/
void set_rate_control_flag(int flag);
/**
* @desc : set the immediate flag
* @params
* flag :
* 1 - immediately start playing from the new location, cancelling any existing PLAY command.
* The first packet sent from the new location shall have the D (discontinuity) bit set in its RTP extension header.
*/
void set_immediate_flag(int flag);
/**
* @desc : set the frame flag
* @params
* flag :
* 0 - all frames
* 1 - I-frame and P-frame
* 2 - I-frame
* interval :
* when flag = 2, set the I-frame interval
*/
void set_frames_flag(int flag, int interval);
/**
* @desc : set replay range
* @params
* start : the replay start timestamp
* end : the replay end timestamp
*/
void set_replay_range(time_t start, time_t end);
void tcp_rx_thread();
void udp_rx_thread();
void rtsp_video_data_cb(uint8 * p_data, int len, uint32 ts, uint32 seq);
void rtsp_audio_data_cb(uint8 * p_data, int len, uint32 ts, uint32 seq);
void rtsp_meta_data_cb(uint8 * p_data, int len, uint32 ts, uint32 seq);
private:
void set_default();
BOOL rtsp_client_start();
void rtsp_client_stop(RCUA * p_rua);
BOOL rtsp_client_state(RCUA * p_rua, HRTSP_MSG * rx_msg);
int rtsp_epoll_rx();
int rtsp_tcp_data_rx(RCUA * p_rua);
int rtsp_over_tcp_rx(RCUA * p_rua);
int rtsp_tcp_rx();
int rtsp_udp_rx();
int rtsp_msg_parser(RCUA * p_rua);
void rtsp_keep_alive();
BOOL rtsp_setup_channel(RCUA * p_rua, int av_t);
BOOL make_prepare_play();
BOOL rtsp_unauth_res(RCUA * p_rua, HRTSP_MSG * rx_msg);
BOOL rtsp_options_res(RCUA * p_rua, HRTSP_MSG * rx_msg);
BOOL rtsp_describe_res(RCUA * p_rua, HRTSP_MSG * rx_msg);
BOOL rtsp_setup_res(RCUA * p_rua, HRTSP_MSG * rx_msg, int av_t);
BOOL rtsp_play_res(RCUA * p_rua, HRTSP_MSG * rx_msg);
BOOL rtsp_init_backchannel(RCUA * p_rua);
BOOL rtsp_get_bc_media_info();
void send_notify(int event);
BOOL rtsp_get_transport_info(RCUA * p_rua, HRTSP_MSG * rx_msg, int av_type);
void rtsp_get_video_size(int * w, int * h);
BOOL rtsp_get_video_media_info();
BOOL rtsp_get_audio_media_info();
void tcp_data_rx(uint8 * lpData, int rlen);
void udp_data_rx(uint8 * lpData, int rlen, int type);
void rtcp_data_rx(uint8 * lpData, int rlen, int type);
void rtsp_send_h264_params(RCUA * p_rua);
void rtsp_send_h265_params(RCUA * p_rua);
void rtsp_get_mpeg4_config(RCUA * p_rua);
void rtsp_get_aac_config(RCUA * p_rua);
int rtsp_build_http_get_req(void * p_user, char * bufs, int buflen, char * cookie);
int rtsp_build_http_post_req(void * p_user, char * bufs, int buflen, char * cookie);
BOOL rtsp_over_http_start();
int rtsp_over_http_rx(RCUA * p_rua);
int rtsp_build_ws_req(void * p_user, char * bufs, int buflen);
BOOL rtsp_over_ws_start();
BOOL rtsp_ws_ping_process(RCUA * p_rua, char * p_buff, int len);
BOOL rtsp_ws_rtsp_process(RCUA * p_rua, char * p_buff, int len);
BOOL rtsp_ws_data_process(RCUA * p_rua);
int rtsp_over_ws_rx(RCUA * p_rua);
private:
RCUA m_rua;
char m_url[256];
char m_ip[128];
char m_suffix[128];
int m_nport;
int m_ep_fd;
struct epoll_event * m_ep_events;
int m_ep_event_num;
notify_cb m_pNotify;
void * m_pUserdata;
video_cb m_pVideoCB;
audio_cb m_pAudioCB;
rtcp_cb m_pRtcpCB;
metadata_cb m_pMetadataCB;
void * m_pMutex;
int m_nRxTimeout;
int m_nConnTimeout;
int m_nWidth;
int m_nHeight;
union {
H264RXI h264rxi;
H265RXI h265rxi;
MJPEGRXI mjpegrxi;
MPEG4RXI mpeg4rxi;
};
union {
AACRXI aacrxi;
PCMRXI pcmrxi;
};
PCMRXI metadatarxi;
BOOL m_bRunning;
pthread_t m_tcpRxTid;
pthread_t m_udpRxTid;
};
#endif // RTSP_CLN_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,152 @@
/***************************************************************************************
*
* 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) 2014-2024, 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.
*
****************************************************************************************/
#ifndef _RTSP_PARSE_H
#define _RTSP_PARSE_H
#include "sys_inc.h"
/*************************************************************************/
typedef enum rtsp_req_mt
{
RTSP_MT_NULL = 0,
RTSP_MT_DESCRIBE,
RTSP_MT_ANNOUNCE,
RTSP_MT_OPTIONS,
RTSP_MT_PAUSE,
RTSP_MT_PLAY,
RTSP_MT_RECORD,
RTSP_MT_REDIRECT,
RTSP_MT_SETUP,
RTSP_MT_SET_PARAMETER,
RTSP_MT_GET_PARAMETER,
RTSP_MT_TEARDOWN
} RTSP_RMT;
typedef struct rtsp_req_message_type_value
{
RTSP_RMT msg_type;
char msg_str[32];
int msg_len;
} RREQMTV;
typedef enum rtsp_context_type
{
RTSP_CTX_NULL = 0,
RTSP_CTX_RTSP,
RTSP_CTX_SDP,
RTSP_CTX_TXT,
RTSP_CTX_HTM,
} RTSPCTXT;
typedef struct hrtsp_msg_content
{
uint32 msg_type; // message type : 0 represents a request, 1 represents a response
uint32 msg_sub_type; // message sub type
HDRV first_line;
PPSN_CTX rtsp_ctx;
PPSN_CTX sdp_ctx;
int rtsp_len;
int sdp_len;
RTSPCTXT ctx_type;
int ctx_len;
char * msg_buf;
int buf_offset;
uint32 remote_ip;
uint16 remote_port;
uint16 local_port;
}HRTSP_MSG;
#ifdef __cplusplus
extern "C" {
#endif
/*************************************************************************/
BOOL rtsp_is_rtsp_msg(char * msg_buf);
void rtsp_headl_parse(char * pline, int llen, HRTSP_MSG * p_msg);
int rtsp_line_parse(char * p_buf, int max_len, char sep_char, PPSN_CTX * p_ctx);
int rtsp_ctx_parse(HRTSP_MSG * p_msg);
int rtsp_msg_parse(char * msg_buf, int msg_buf_len, HRTSP_MSG * msg);
int rtsp_msg_parse_part1(char * p_buf, int buf_len, HRTSP_MSG * msg);
int rtsp_msg_parse_part2(char * p_buf, int buf_len, HRTSP_MSG * msg);
/*************************************************************************/
HDRV * rtsp_find_headline(HRTSP_MSG * msg, const char * head);
HDRV * rtsp_find_headline_next(HRTSP_MSG * msg, const char * head, HDRV * hrv);
HDRV * rtsp_find_sdp_headline(HRTSP_MSG * msg, const char * head);
BOOL rtsp_msg_with_sdp(HRTSP_MSG * msg);
BOOL rtsp_match_msg_session(HRTSP_MSG * rx_msg, HRTSP_MSG * tx_msg);
BOOL rtsp_match_msg_cseq(HRTSP_MSG * rx_msg, HRTSP_MSG * tx_msg);
BOOL rtsp_get_headline_uri(HRTSP_MSG * rx_msg, char * p_uri, int size);
BOOL rtsp_get_headline_string(HRTSP_MSG * rx_msg, const char * head, char * p_value, int size);
BOOL rtsp_get_msg_session(HRTSP_MSG * rx_msg, char *session_buf, int len);
BOOL rtsp_get_msg_cseq(HRTSP_MSG * rx_msg, char *cseq_buf, int len);
BOOL rtsp_get_user_agent_info(HRTSP_MSG * rx_msg, char * agent_buf, int max_len);
BOOL rtsp_get_session_info(HRTSP_MSG * rx_msg, char * session_buf, int max_len, int * timeout);
BOOL rtsp_get_rtp_info(HRTSP_MSG * rx_msg, char * v_ctl, uint32 * p_v_ts, char * a_ctl, uint32 * p_a_ts);
BOOL rtsp_get_tcp_transport_info(HRTSP_MSG * rx_msg, uint16 *interleaved);
BOOL rtsp_get_udp_transport_info(HRTSP_MSG * rx_msg, uint16 *client_port, uint16 *server_port);
BOOL rtsp_get_mc_transport_info(HRTSP_MSG * rx_msg, char *destination, uint16 *port);
BOOL rtsp_get_cbase_info(HRTSP_MSG * rx_msg, char * cbase_buf, int max_len);
BOOL rtsp_get_digest_info(HRTSP_MSG * rx_msg, HD_AUTH_INFO * auth_info);
BOOL rtsp_get_auth_digest_info(HRTSP_MSG * rx_msg, HD_AUTH_INFO * p_auth);
BOOL rtsp_is_line_exist(HRTSP_MSG * rx_msg, const char * head, const char * value);
void rtsp_add_tx_msg_line(HRTSP_MSG * tx_msg, const char * msg_hdr, const char * msg_fmt, ...);
void rtsp_add_tx_msg_sdp_line(HRTSP_MSG * tx_msg, const char * msg_hdr, const char * msg_fmt, ...);
void rtsp_add_tx_msg_fline(HRTSP_MSG * tx_msg, const char * msg_hdr, const char * msg_fmt, ...);
void rtsp_copy_msg_line(HRTSP_MSG * src_msg, HRTSP_MSG * dst_msg, const char * msg_hdr);
void rtsp_free_msg(HRTSP_MSG * msg);
void rtsp_free_msg_content(HRTSP_MSG * msg);
/*************************************************************************/
BOOL rtsp_get_remote_media_ip(HRTSP_MSG * rx_msg, uint32 * media_ip);
HDRV * rtsp_find_mdesc_point(HRTSP_MSG * rx_msg, HDRV * pStartHdr, const char * cap_name, int * next_offset, const char * attr=NULL);
BOOL rtsp_get_remote_cap(HRTSP_MSG * rx_msg, const char * cap_name, int * cap_count, uint8 * cap_array, uint16 * rtp_port, const char * attr=NULL);
BOOL rtsp_get_remote_cap_desc(HRTSP_MSG * rx_msg, const char * cap_name, char cap_desc[][MAX_AVDESCLEN], const char * attr=NULL);
BOOL rtsp_find_sdp_control(HRTSP_MSG * rx_msg, char * ctl_buf, const char * tname, int max_len, const char *attr = NULL);
BOOL rtsp_get_sdp_range(HRTSP_MSG * rx_msg, int * p_start, int * p_end);
BOOL rtsp_is_support_mcast(HRTSP_MSG * rx_msg);
BOOL rtsp_get_scale_info(HRTSP_MSG * rx_msg, int * p_scale);
BOOL rtsp_get_rate_control(HRTSP_MSG * rx_msg, int * p_ratectrl);
BOOL rtsp_get_immediate(HRTSP_MSG * rx_msg, int * p_imme);
BOOL rtsp_get_frame_info(HRTSP_MSG * rx_msg, int * p_frame, int * p_interval);
/*************************************************************************/
BOOL rtsp_msg_buf_init(int num);
void rtsp_msg_buf_deinit();
HRTSP_MSG * rtsp_get_msg_buf();
void rtsp_msg_ctx_init(HRTSP_MSG * msg);
void rtsp_free_msg_buf(HRTSP_MSG * msg);
uint32 rtsp_idle_msg_buf_num();
BOOL rtsp_parse_buf_init(int nums);
void rtsp_parse_buf_deinit();
#ifdef __cplusplus
}
#endif
#endif // _RTSP_PARSE_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,243 @@
/***************************************************************************************
*
* 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) 2014-2024, 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.
*
****************************************************************************************/
#ifndef RTSP_RCUA_H
#define RTSP_RCUA_H
#include "rtsp_parse.h"
#include "http.h"
#ifdef BACKCHANNEL
#include "audio_capture.h"
#endif
#ifdef OVER_WEBSOCKET
#include "rtsp_ws.h"
#endif
#define AV_TYPE_VIDEO 0
#define AV_TYPE_AUDIO 1
#define AV_TYPE_METADATA 2
#define AV_TYPE_BACKCHANNEL 3
#define AV_MAX_CHS 4
#define AV_VIDEO_CH AV_TYPE_VIDEO
#define AV_AUDIO_CH AV_TYPE_AUDIO
#define AV_METADATA_CH AV_TYPE_METADATA
#define AV_BACK_CH AV_TYPE_BACKCHANNEL
/**
* RTSP over websocket needs to reserve some space
* in the header of the send buffer
*/
#define RTSP_SND_RESV_SIZE 32
typedef enum rtsp_client_states
{
RCS_NULL = 0,
RCS_OPTIONS,
RCS_DESCRIBE,
RCS_INIT_V,
RCS_INIT_A,
RCS_INIT_M,
RCS_INIT_BC,
RCS_READY,
RCS_PLAYING,
RCS_RECORDING,
} RCSTATE;
typedef struct rtsp_client_media_channel
{
int disabled; // not setup this channel
SOCKET udp_fd; // udp socket
SOCKET rtcp_fd; // rtcp udp socket
char ctl[128]; // control string
uint16 setup; // whether the media channel already be setuped
uint16 r_port; // remote udp port
uint16 l_port; // local udp port
uint16 interleaved; // rtp channel values
char destination[32]; // multicast address
int cap_count; // Local number of capabilities
uint8 cap[MAX_AVN]; // Local capability
char cap_desc[MAX_AVN][MAX_AVDESCLEN];
} RCMCH;
typedef struct rtsp_client_user_agent
{
uint32 used_flag : 1; // used flag
uint32 rtp_tcp : 1; // rtp over tcp
uint32 mcast_flag : 1; // use rtp multicast, set by user
uint32 rtp_mcast : 1; // use rtp multicast, set by stack
uint32 rtp_tx : 1; // rtp sending flag
uint32 need_auth : 1; // need auth flag
uint32 auth_mode : 2; // 0 - baisc; 1 - digest
uint32 gp_cmd : 1; // is support get_parameter command
uint32 backchannel : 1; // audio backchannle flag
uint32 send_bc_data: 1; // audio backchannel data sending flag
uint32 replay : 1; // replay flag
uint32 over_http : 1; // rtsp over http flag
uint32 over_ws : 1; // rtsp over websocket flag
uint32 auth_retry : 3; // auth retry numbers
uint32 reserved : 15;
int state; // state, RCSTATE
SOCKET fd; // socket handler
uint32 keepalive_time; // keepalive time
char ripstr[128]; // remote ip
uint16 rport; // rtsp server port
uint32 cseq; // seq no
char sid[64]; // Session ID
char uri[256]; // rtsp://221.10.50.195:554/cctv.sdp
char cbase[256]; // Content-Base: rtsp://221.10.50.195:554/broadcast.sdp/
char user_agent[64]; // user agent string
int session_timeout; // session timeout value
int play_start; // a=range:npt=0-20.735, unit is millisecond
int play_end; // a=range:npt=0-20.735, unit is millisecond
uint32 video_init_ts; // video init timestampe
uint32 audio_init_ts; // audio init timestampe
int seek_pos; // seek pos
int media_start; // media start time, unit is millisecond
char rcv_buf[2052]; // receive buffer
int rcv_dlen; // receive data length
int rtp_t_len; // rtp payload total length
int rtp_rcv_len; // rtp payload receive length
char * rtp_rcv_buf; // rtp payload receive buffer
RCMCH channels[AV_MAX_CHS]; // media channels
HD_AUTH_INFO auth_info; // auth information
int video_codec; // video codec
int audio_codec; // audio codec
int sample_rate; // audio sample rate
int audio_channels; // audio channels
int bit_per_sample; // audio bit per sample
uint8 * audio_spec; // audio special data, for AAC etc.
uint32 audio_spec_len; // audio special data length
#ifdef BACKCHANNEL
int bc_audio_device; // back channel audio device index, start from 0
int bc_audio_codec; // back channel audio codec
int bc_sample_rate; // back channel sample rate
int bc_channels; // back channel channel numbers
int bc_bit_per_sample; // back channel bit per sample
UA_RTP_INFO bc_rtp_info; // back channel audio rtp info
CAudioCapture * audio_captrue; // audio capture
#endif
#ifdef REPLAY
uint32 scale_flag : 1;
uint32 rate_control_flag : 1;
uint32 immediate_flag : 1;
uint32 frame_flag : 1;
uint32 frame_interval_flag : 1;
uint32 range_flag : 1;
uint32 replay_reserved : 26;
int scale; // scale info, when not set the rata control flag, the scale is valid.
// It shall be either 100.0 or -100.0, to indicate forward or reverse playback respectively.
// If it is not present, forward playback is assumed
// 100 means 1.0, Divide by 100 when using
int rate_control; // rate control flag,
// 1-the stream is delivered in real time using standard RTP timing mechanisms
// 0-the stream is delivered as fast as possible, using only the flow control provided by the transport to limit the delivery rate
int immediate; // 1 - immediately start playing from the new location, cancelling any existing PLAY command.
// The first packet sent from the new location shall have the D (discontinuity) bit set in its RTP extension header.
int frame; // 0 - all frames
// 1 - I-frame and P-frame
// 2 - I-frame
int frame_interval; // I-frame interval, unit is milliseconds
time_t replay_start; // replay start time
time_t replay_end; // replay end time
#endif
#ifdef OVER_HTTP
uint16 http_port; // rtsp over http port
HTTPREQ rtsp_send; // rtsp over http get connection
HTTPREQ rtsp_recv; // rtsp over http post connection
#endif
#ifdef OVER_WEBSOCKET
uint16 ws_port; // rtsp over websocket port
HTTPREQ ws_http; // rtsp over websocket connection
WSMSG ws_msg; // rtsp over websocket message handler
#endif
} RCUA;
#ifdef __cplusplus
extern "C" {
#endif
/*************************************************************************/
HRTSP_MSG * rcua_build_describe(RCUA * p_rua);
HRTSP_MSG * rcua_build_setup(RCUA * p_rua,int type);
HRTSP_MSG * rcua_build_play(RCUA * p_rua);
HRTSP_MSG * rcua_build_pause(RCUA * p_rua);
HRTSP_MSG * rcua_build_teardown(RCUA * p_rua);
HRTSP_MSG * rcua_build_get_parameter(RCUA * p_rua);
HRTSP_MSG * rcua_build_options(RCUA * p_rua);
/*************************************************************************/
BOOL rcua_get_media_info(RCUA * p_rua, HRTSP_MSG * rx_msg);
BOOL rcua_get_sdp_video_desc(RCUA * p_rua, const char * key, int * pt, char * p_sdp, int max_len);
BOOL rcua_get_sdp_audio_desc(RCUA * p_rua, const char * key, int * pt, char * p_sdp, int max_len);
BOOL rcua_get_sdp_h264_desc(RCUA * p_rua, int * pt, char * p_sdp, int max_len);
BOOL rcua_get_sdp_h264_params(RCUA * p_rua, int * pt, char * p_sps_pps, int max_len);
BOOL rcua_get_sdp_h265_desc(RCUA * p_rua, int * pt, char * p_sdp, int max_len);
BOOL rcua_get_sdp_h265_params(RCUA * p_rua, int * pt, BOOL * donfield, char * p_vps, int vps_len, char * p_sps, int sps_len, char * p_pps, int pps_len);
BOOL rcua_get_sdp_mp4_desc(RCUA * p_rua, int * pt, char * p_sdp, int max_len);
BOOL rcua_get_sdp_mp4_params(RCUA * p_rua, int * pt, char * p_cfg, int max_len);
BOOL rcua_get_sdp_aac_desc(RCUA * p_rua, int * pt, char * p_sdp, int max_len);
BOOL rcua_get_sdp_aac_params(RCUA * p_rua, int *pt, int *sizelength, int *indexlength, int *indexdeltalength, char * p_cfg, int max_len);
SOCKET rcua_init_udp_connection(uint16 port);
SOCKET rcua_init_mc_connection(uint16 port, char * destination);
/*************************************************************************/
void rcua_send_rtsp_msg(RCUA * p_rua,HRTSP_MSG * tx_msg);
#define rcua_send_free_rtsp_msg(p_rua,tx_msg) \
do { \
rcua_send_rtsp_msg(p_rua,tx_msg); \
rtsp_free_msg(tx_msg); \
} while(0)
#ifdef __cplusplus
}
#endif
#endif // RTSP_RCUA_H

View File

@@ -0,0 +1,258 @@
/***************************************************************************************
*
* 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) 2014-2024, 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 "sys_inc.h"
#include "rtsp_util.h"
/***********************************************************************/
#define UDP_BASE_PORT 40000
static uint16 g_udp_bport = UDP_BASE_PORT;
static void * g_udp_port_mutex = sys_os_create_mutex();
/***********************************************************************/
uint16 rtsp_get_udp_port()
{
uint16 port;
sys_os_mutex_enter(g_udp_port_mutex);
port = g_udp_bport;
g_udp_bport += 2;
if (g_udp_bport > 65534)
{
g_udp_bport = UDP_BASE_PORT;
}
sys_os_mutex_leave(g_udp_port_mutex);
return port;
}
uint32 rtsp_get_timestamp(int frequency)
{
struct timeval tv;
gettimeofday(&tv, 0);
// Begin by converting from "struct timeval" units to RTP timestamp units:
uint32 increment = (frequency*tv.tv_sec);
increment += (uint32)(frequency*(tv.tv_usec/1000000.0) + 0.5); // note: rounding
return increment;
}
char * rtsp_get_utc_time()
{
static char buff[100];
time_t t = time(NULL);
struct tm *ptr = gmtime(&t);
strftime(buff, sizeof(buff)-1, "%a, %b %d %Y %H:%M:%S GMT", ptr);
return buff;
}
int rtsp_pkt_find_end(char * p_buf)
{
int end_off = 0;
int rtsp_pkt_finish = 0;
while (p_buf[end_off] != '\0')
{
if ((p_buf[end_off+0] == '\r' && p_buf[end_off+1] == '\n') &&
(p_buf[end_off+2] == '\r' && p_buf[end_off+3] == '\n'))
{
rtsp_pkt_finish = 1;
break;
}
end_off++;
}
if (rtsp_pkt_finish)
{
return(end_off + 4);
}
return 0;
}
time_t rtsp_timegm(struct tm *T)
{
time_t t, g, z;
struct tm tm;
t = mktime(T);
if (t == (time_t)-1)
{
return (time_t)-1;
}
tm = *gmtime(&t);
tm.tm_isdst = 0;
g = mktime(&tm);
if (g == (time_t)-1)
{
return (time_t)-1;
}
z = g - t;
return t - z;
}
BOOL rtsp_parse_xsd_datetime(const char * s, time_t * p)
{
if (s)
{
char zone[32];
struct tm T;
const char *t;
*zone = '\0';
memset(&T, 0, sizeof(T));
if (strchr(s, '-'))
{
t = "%d-%d-%dT%d:%d:%d%31s";
}
else if (strchr(s, ':'))
{
t = "%4d%2d%2dT%d:%d:%d%31s";
}
else /* parse non-XSD-standard alternative ISO 8601 format */
{
t = "%4d%2d%2dT%2d%2d%2d%31s";
}
if (sscanf(s, t, &T.tm_year, &T.tm_mon, &T.tm_mday, &T.tm_hour, &T.tm_min, &T.tm_sec, zone) < 6)
{
return FALSE;
}
if (T.tm_year == 1)
{
T.tm_year = 70;
}
else
{
T.tm_year -= 1900;
}
T.tm_mon--;
if (*zone == '.')
{
for (s = zone + 1; *s; s++)
{
if (*s < '0' || *s > '9')
{
break;
}
}
}
else
{
s = zone;
}
if (*s)
{
if (*s == '+' || *s == '-')
{
int h = 0, m = 0;
if (s[3] == ':')
{
/* +hh:mm */
sscanf(s, "%d:%d", &h, &m);
if (h < 0)
m = -m;
}
else /* +hhmm */
{
m = (int)strtol(s, NULL, 10);
h = m / 100;
m = m % 100;
}
T.tm_min -= m;
T.tm_hour -= h;
/* put hour and min in range */
T.tm_hour += T.tm_min / 60;
T.tm_min %= 60;
if (T.tm_min < 0)
{
T.tm_min += 60;
T.tm_hour--;
}
T.tm_mday += T.tm_hour / 24;
T.tm_hour %= 24;
if (T.tm_hour < 0)
{
T.tm_hour += 24;
T.tm_mday--;
}
/* note: day of the month may be out of range, timegm() handles it */
}
*p = rtsp_timegm(&T);
}
else /* no UTC or timezone, so assume we got a localtime */
{
T.tm_isdst = -1;
*p = mktime(&T);
}
}
return TRUE;
}
int64 rtsp_gettime()
{
#if __LINUX_OS__
struct timeval tv;
gettimeofday(&tv, NULL);
return (int64)tv.tv_sec * 1000000 + tv.tv_usec;
#elif __WINDOWS_OS__
FILETIME ft;
int64 t;
GetSystemTimeAsFileTime(&ft);
t = (int64)ft.dwHighDateTime << 32 | ft.dwLowDateTime;
return t / 10 - 11644473600000000; /* Jan 1, 1601 */
#endif
return -1;
}
uint64 rtsp_ntp_time()
{
return (rtsp_gettime() / 1000) * 1000 + NTP_OFFSET_US;
}

View File

@@ -0,0 +1,47 @@
/***************************************************************************************
*
* 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) 2014-2024, 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.
*
****************************************************************************************/
#ifndef RTSP_UTIL_H
#define RTSP_UTIL_H
#define NTP_OFFSET 2208988800ULL
#define NTP_OFFSET_US (NTP_OFFSET * 1000000ULL)
#ifdef __cplusplus
extern "C" {
#endif
uint16 rtsp_get_udp_port();
uint32 rtsp_get_timestamp(int frequency);
char * rtsp_get_utc_time();
int rtsp_pkt_find_end(char * p_buf);
BOOL rtsp_parse_xsd_datetime(const char * s, time_t * p);
int64 rtsp_gettime();
uint64 rtsp_ntp_time();
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,211 @@
/***************************************************************************************
*
* 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) 2014-2024, 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 "sys_inc.h"
#include "rtsp_ws.h"
#include "rtp.h"
int rtsp_ws_decode_data(WSMSG * p_msg)
{
int length, has_mask;
char * p_buff = p_msg->buff;
/**
* Extracting information from frame
*/
has_mask = p_buff[1] & 0x80 ? 1 : 0;
length = p_buff[1] & 0x7f;
p_msg->opcode = (p_buff[0] & 0xF);
p_msg->finbit = ((p_buff[0] & 0x80) ? 1 : 0);
/**
* We need to handle the received frame differently according to which
* length that the frame has set.
*
* length <= 125: We know that length is the actual length of the message,
* and that the maskin data must be placed 2 bytes further
* ahead.
* length == 126: We know that the length is an unsigned 16 bit integer,
* which is placed at the 2 next bytes, and that the masking
* data must be further 2 bytes away.
* length == 127: We know that the length is an unsigned 64 bit integer,
* which is placed at the 8 next bytes, and that the masking
* data must be further 2 bytes away.
*/
if (length <= 125)
{
if (p_msg->rcv_len < 6)
{
return 0;
}
p_msg->msg_len = length;
p_msg->skip = 2;
if (has_mask)
{
p_msg->skip += 4;
memcpy(&p_msg->mask, p_buff + 2, sizeof(p_msg->mask));
}
}
else if (length == 126)
{
if (p_msg->rcv_len < 8)
{
return 0;
}
p_msg->msg_len = rtp_read_uint16((uint8 *)p_buff + 2);
p_msg->skip = 4;
if (has_mask)
{
p_msg->skip += 4;
memcpy(&p_msg->mask, p_buff + 4, sizeof(p_msg->mask));
}
}
else if (length == 127)
{
if (p_msg->rcv_len < 14)
{
return 0;
}
p_msg->msg_len = (uint32)rtp_read_uint64((uint8 *)p_buff + 2);
p_msg->skip = 10;
if (has_mask)
{
p_msg->skip += 4;
memcpy(&p_msg->mask, p_buff + 10, sizeof(p_msg->mask));
}
}
else
{
log_print(HT_LOG_ERR, "%s, Obscure length received from client: %d\r\n", __FUNCTION__, length);
return -1;
}
/**
* If the message length is greater that our WS_MAXMESSAGE constant, we
* skip the message and close the connection.
*/
if (p_msg->msg_len > WS_MAXMESSAGE)
{
log_print(HT_LOG_ERR, "%s, Message received was bigger than WS_MAXMESSAGE\r\n", __FUNCTION__);
return -1;
}
uint32 buf_len = (p_msg->rcv_len - p_msg->skip);
/**
* The message read from recv is larger than the message we are supposed
* to receive. This means that we have received the first part of the next
* message as well.
*/
if (buf_len >= p_msg->msg_len)
{
if (has_mask)
{
char * buff = p_msg->buff + p_msg->skip;
/**
* If everything went well, we have to remove the masking from the data.
*/
for (uint32 i = 0; i < p_msg->msg_len; i++)
{
buff[i] = buff[i] ^ p_msg->mask[i % 4];
}
}
return 1;
}
return 0;
}
/***
* websocket encod data, add websocket header before p_data
* The p_data pointer must reserve a certain amount of space
*/
int rtsp_ws_encode_data(uint8 * p_data, int len, uint8 opcode, uint8 have_mask)
{
int offset = 0;
uint8 mask[4];
if (have_mask)
{
mask[0] = rand();
mask[1] = rand();
mask[2] = rand();
mask[3] = rand();
for (int32 i = 0; i < len; i++)
{
p_data[i] = p_data[i] ^ mask[i % 4];
}
}
/**
* RFC6455 message encoding
*/
if (len <= 125)
{
p_data -= have_mask ? 6 : 2;
p_data[0] = opcode;
p_data[1] = have_mask ? (len | 0x80) : len;
if (have_mask)
{
memcpy(p_data+2, mask, 4);
}
offset = have_mask ? 6 : 2;
}
else if (len <= 65535)
{
p_data -= have_mask ? 8 : 4;
p_data[0] = opcode;
p_data[1] = have_mask ? (126 | 0x80) : 126;
rtp_write_uint16(p_data + 2, len);
if (have_mask)
{
memcpy(p_data+4, mask, 4);
}
offset = have_mask ? 8 : 4;
}
else
{
uint64 len64 = len;
p_data -= have_mask ? 14 : 10;
p_data[0] = opcode;
p_data[1] = have_mask ? (127 | 0x80) : 127;
rtp_write_uint32(p_data + 2, len64 & 0xFFFF);
rtp_write_uint32(p_data + 6, (len64 >> 32) & 0xFFFF);
if (have_mask)
{
memcpy(p_data+10, mask, 4);
}
offset = have_mask ? 14 : 10;
}
return offset;
}

View File

@@ -0,0 +1,62 @@
/***************************************************************************************
*
* 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) 2014-2024, 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.
*
****************************************************************************************/
#ifndef RTSP_WS_H
#define RTSP_WS_H
#include "sys_inc.h"
/**************************************************************************************/
#define WS_VERSION 13 // websocket version
#define WS_PROTOCOL "rtsp.onvif.org" // websocket protocol
#define WS_MAXMESSAGE 1048576 // Max size message = 1MB
/**************************************************************************************/
typedef struct
{
uint32 finbit : 1;
uint32 opcode : 4;
uint32 reserved : 27;
char mask[4];
int skip;
uint32 buff_len;
uint32 rcv_len;
uint32 msg_len;
char * buff;
} WSMSG;
#ifdef __cplusplus
extern "C" {
#endif
int rtsp_ws_decode_data(WSMSG * p_msg);
int rtsp_ws_encode_data(uint8 * p_data, int len, uint8 opcode, uint8 have_mask);
#ifdef __cplusplus
}
#endif
#endif