Files
ANSCORE/MediaClient/rtsp/rtsp_backchannel.cpp

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