338 lines
7.4 KiB
C++
338 lines
7.4 KiB
C++
/***************************************************************************************
|
|
*
|
|
* 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
|
|
|
|
|
|
|